From 58f72fdf18a92d4557998c54b709198181cde931 Mon Sep 17 00:00:00 2001 From: Eiffel-World Date: Thu, 30 Jun 2011 02:09:51 -0700 Subject: [PATCH 001/178] Initial Commit --- Home.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Home.md diff --git a/Home.md b/Home.md new file mode 100644 index 00000000..e5a0dc6f --- /dev/null +++ b/Home.md @@ -0,0 +1 @@ +Welcome to the Eiffel-Web-Framework wiki! \ No newline at end of file From 509375f7e67727748afc5cde81cef7590e5638fa Mon Sep 17 00:00:00 2001 From: jocelyn Date: Thu, 30 Jun 2011 02:24:23 -0700 Subject: [PATCH 002/178] Updated Home (markdown) --- Home.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Home.md b/Home.md index e5a0dc6f..4dba1c7c 100644 --- a/Home.md +++ b/Home.md @@ -1 +1,5 @@ -Welcome to the Eiffel-Web-Framework wiki! \ No newline at end of file += Eiffel-Web-Framework = + +![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) + +**Eiffel Web Framework**: Please visit the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] \ No newline at end of file From 1782fc9f4debcc3583c6392f8a224b6ac268cf4c Mon Sep 17 00:00:00 2001 From: jocelyn Date: Thu, 30 Jun 2011 02:24:59 -0700 Subject: [PATCH 003/178] Updated Home (markdown) --- Home.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Home.md b/Home.md index 4dba1c7c..eed80a79 100644 --- a/Home.md +++ b/Home.md @@ -1,5 +1,3 @@ -= Eiffel-Web-Framework = +# Eiffel-Web-Framework -![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) - -**Eiffel Web Framework**: Please visit the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] \ No newline at end of file +**Eiffel Web Framework**: Please visit the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) \ No newline at end of file From aca99fe6d4947e0182ae2457b15777fcc8dc9540 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 5 Jul 2011 02:37:56 -0700 Subject: [PATCH 004/178] Created Tasks (markdown) --- Tasks.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Tasks.md diff --git a/Tasks.md b/Tasks.md new file mode 100644 index 00000000..8de57910 --- /dev/null +++ b/Tasks.md @@ -0,0 +1,36 @@ +## October 1st ## +* Source code , layout/handling EWR (**jfiat**) +* "Eiffel WSGI" spec (github wiki) (**paco**) +* Eiffel Web Nino (**jvelilla**) +* REST component (**jfiat**) +* Example/reference Eiffel Web Server App (**jvelilla**) + - Hello World + - Restbucks (from the book REST in Practice) +* WAMIE/apache based support for Eiffel WSGI (**daro**) + - SCOOP ... +* Some persistance solution (**daro**) +* XML, JSON support (**jvelilla**) + +## Maybe for October 1st ## +* Reference Client/REST-service consumer + - Mashup support, facebook, twitter, google+, ... (**jfiat**) +* Authentication support + - OpenID, Google Connect, Facebook Connect, OAuth, ... + - http authorization + +## December ## +* Session handling + - Cookie based + - REST-based session example +* Access Control +* Application builder + - Deployment + - Persistence chooser +* Dynamic update of running system (**daro**) + + +## Contributors ## + - jfiat = Jocelyn Fiat + - paco = Paul Cohen + - daro = Daniel Rodriguez + - jvelilla = Hector Javier Velilla \ No newline at end of file From 23d8adaa3df901a246174e449e4b4ae81bb37e48 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 5 Jul 2011 02:38:05 -0700 Subject: [PATCH 005/178] Updated Tasks (markdown) --- Tasks.md => Tasks---Roadmap.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Tasks.md => Tasks---Roadmap.md (100%) diff --git a/Tasks.md b/Tasks---Roadmap.md similarity index 100% rename from Tasks.md rename to Tasks---Roadmap.md From 057cec2b4470126e778b5189b4c9f7a015dfc607 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 5 Jul 2011 02:38:30 -0700 Subject: [PATCH 006/178] Updated Tasks Roadmap (markdown) --- Tasks---Roadmap.md => Tasks-Roadmap.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Tasks---Roadmap.md => Tasks-Roadmap.md (100%) diff --git a/Tasks---Roadmap.md b/Tasks-Roadmap.md similarity index 100% rename from Tasks---Roadmap.md rename to Tasks-Roadmap.md From 0b7165b2603df82d7f1b1bb99caeb615d70a448b Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 5 Jul 2011 02:40:41 -0700 Subject: [PATCH 007/178] Updated Eiffel-Web-Framework (markdown) --- Home.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Home.md b/Home.md index eed80a79..ae51a3c5 100644 --- a/Home.md +++ b/Home.md @@ -1,3 +1,5 @@ -# Eiffel-Web-Framework +## Eiffel-Web-Framework ## -**Eiffel Web Framework**: Please visit the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) \ No newline at end of file +- **Eiffel Web Framework**: Please visit the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) + +- See a first [[list of tasks, and a potential roadmap| Tasks-Roadmap]] \ No newline at end of file From d9b52d2691da3a66819ea64d793a3a00a1d44ebb Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 5 Jul 2011 02:43:47 -0700 Subject: [PATCH 008/178] Updated Tasks Roadmap (markdown) --- Tasks-Roadmap.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Tasks-Roadmap.md b/Tasks-Roadmap.md index 8de57910..19788960 100644 --- a/Tasks-Roadmap.md +++ b/Tasks-Roadmap.md @@ -12,9 +12,9 @@ * XML, JSON support (**jvelilla**) ## Maybe for October 1st ## -* Reference Client/REST-service consumer - - Mashup support, facebook, twitter, google+, ... (**jfiat**) -* Authentication support +* Reference Client/REST-service consumer (**jfiat**) +* Mashup support, facebook, twitter, google+, ... (**jfiat**) +* Authentication support (**jfiat** ?) - OpenID, Google Connect, Facebook Connect, OAuth, ... - http authorization @@ -30,7 +30,9 @@ ## Contributors ## - - jfiat = Jocelyn Fiat - - paco = Paul Cohen - - daro = Daniel Rodriguez - - jvelilla = Hector Javier Velilla \ No newline at end of file + - **jfiat** = Jocelyn Fiat + - **paco** = Paul Cohen + - **daro** = Daniel Rodriguez + - **jvelilla** = Hector Javier Velilla + +note: In bold, you see the responsible for each task, but contribution from other is possible as well. \ No newline at end of file From 71cdfe18abd9feca282757cfb6489001d7fbb216 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 5 Jul 2011 05:01:45 -0700 Subject: [PATCH 009/178] Updated Home (markdown) --- Home.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Home.md b/Home.md index ae51a3c5..7fdb90c7 100644 --- a/Home.md +++ b/Home.md @@ -1,5 +1,8 @@ ## Eiffel-Web-Framework ## +The official documentation/wiki is located at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki , if you are visiting a "clone/fork", please always check the [[original wiki|https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki]]. + + - **Eiffel Web Framework**: Please visit the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) - See a first [[list of tasks, and a potential roadmap| Tasks-Roadmap]] \ No newline at end of file From 7f35ca21e27ee3469f7f9a59eb0bd5b9a0643b87 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 5 Jul 2011 05:22:01 -0700 Subject: [PATCH 010/178] Updated Home (markdown) --- Home.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Home.md b/Home.md index 7fdb90c7..6a6f305e 100644 --- a/Home.md +++ b/Home.md @@ -5,4 +5,5 @@ The official documentation/wiki is located at https://github.com/Eiffel-World/Ei - **Eiffel Web Framework**: Please visit the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) -- See a first [[list of tasks, and a potential roadmap| Tasks-Roadmap]] \ No newline at end of file +- See a first [[list of tasks, and a potential roadmap| Tasks-Roadmap]] +- See also a [[General source structure of this project| Source-structure]] \ No newline at end of file From f9a79c080044d3d729c685e9b09b03530445046c Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 5 Jul 2011 05:31:59 -0700 Subject: [PATCH 011/178] Created Source structure (markdown) --- Source-structure.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Source-structure.md diff --git a/Source-structure.md b/Source-structure.md new file mode 100644 index 00000000..80da56a1 --- /dev/null +++ b/Source-structure.md @@ -0,0 +1,27 @@ +## Currently ## + +- LICENSE : file containing the global license +- README : quick README to point to the github project +- doc/ +- doc/wiki : clone of the associated github wiki repository +- example/ +- test/ +- library/ +- library/ewsgi/ewsgi.ecf +- library/ewsgi/ewsgi.ecf + +Any library/component (in development mode) should follow the following structure (when not needed, there is no need to create the associated folder(s) ): +- **README** +- **COPYRIGHT** +- **LICENSE** +- **.ecf** and **-safe.ecf** +- **library/** : the place to put the source code of the related library/component +- **doc/** : notes, documentations, ... +- **test/** : standard place to put your tests, if you are using Eiffel Software auto-tests, I would suggest to add a new target into the associated .ecf (instead of building a new .ecf under test/ ) +- **example/** : standard place to put the example +- **build/** : a convenient place to compile your project, using this convention, you can setup utilities such as backup to ignore this folder. +- **resource/** : contains pixmap files, .... +- **install/** : contains installation scripts for each platform +- **data/** : contains eventual data for the related tools + +See that we use the singular, since it is an Eiffel convention for naming cluster or folder. From e0eedef3a76394a371a60879a1bacf70175e68f5 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 5 Jul 2011 05:33:22 -0700 Subject: [PATCH 012/178] Updated Source structure (markdown) --- Source-structure.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source-structure.md b/Source-structure.md index 80da56a1..1314e608 100644 --- a/Source-structure.md +++ b/Source-structure.md @@ -11,10 +11,11 @@ - library/ewsgi/ewsgi.ecf Any library/component (in development mode) should follow the following structure (when not needed, there is no need to create the associated folder(s) ): + - **README** - **COPYRIGHT** - **LICENSE** -- **.ecf** and **-safe.ecf** +- **.ecf** and **-safe.ecf** : configuration file - **library/** : the place to put the source code of the related library/component - **doc/** : notes, documentations, ... - **test/** : standard place to put your tests, if you are using Eiffel Software auto-tests, I would suggest to add a new target into the associated .ecf (instead of building a new .ecf under test/ ) From 5f5a8c6dafc821b9ed57ba3a32aeb893b799b031 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 5 Jul 2011 05:34:06 -0700 Subject: [PATCH 013/178] Updated Tasks Roadmap (markdown) --- Tasks-Roadmap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tasks-Roadmap.md b/Tasks-Roadmap.md index 19788960..9f921e84 100644 --- a/Tasks-Roadmap.md +++ b/Tasks-Roadmap.md @@ -9,7 +9,7 @@ * WAMIE/apache based support for Eiffel WSGI (**daro**) - SCOOP ... * Some persistance solution (**daro**) -* XML, JSON support (**jvelilla**) +* XML, [[JSON|Task-JSON]] support (**jvelilla**) ## Maybe for October 1st ## * Reference Client/REST-service consumer (**jfiat**) From c9c2b37070c8acd2544669c071e0e00dc18a0f33 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 5 Jul 2011 05:37:20 -0700 Subject: [PATCH 014/178] Created Task json (markdown) --- Task-json.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 Task-json.md diff --git a/Task-json.md b/Task-json.md new file mode 100644 index 00000000..e8c22725 --- /dev/null +++ b/Task-json.md @@ -0,0 +1,10 @@ +## Goal ## +- Make this JSON library the default one for the community + +## Steps ## +- restructure to follow the (doc,library,test,...) structure +- extract gobo from it, and provide json.ecf, json-safe.ecf, json_with_gobo.ecf (and json_with_gobo-safe.ecf : not possible right now, but we can _cheat_) +- and then let Eiffel Software include it, in the official libraries + +## Roadmap ## +- this should be done before 1st of October \ No newline at end of file From baae1daa855dd3c7395bf1d0b6b22e79fdd693b5 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Wed, 6 Jul 2011 11:03:21 +0200 Subject: [PATCH 015/178] Added server side architecture for EWSGI --- server_architecture.png | Bin 0 -> 89726 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 server_architecture.png diff --git a/server_architecture.png b/server_architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..3128400d777b70d9dd8c13604af1de82d0b0a287 GIT binary patch literal 89726 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 A#sB~S literal 0 HcmV?d00001 From 6bdfb1d74a60de6005c99ee2d36bd98263a13ea9 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 6 Jul 2011 02:05:17 -0700 Subject: [PATCH 016/178] Updated Home (markdown) --- Home.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Home.md b/Home.md index 6a6f305e..34e6ebc0 100644 --- a/Home.md +++ b/Home.md @@ -6,4 +6,6 @@ The official documentation/wiki is located at https://github.com/Eiffel-World/Ei - **Eiffel Web Framework**: Please visit the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) - See a first [[list of tasks, and a potential roadmap| Tasks-Roadmap]] -- See also a [[General source structure of this project| Source-structure]] \ No newline at end of file +- See also + - [[General source structure of this project| Source-structure]] + - [[Overview of the server side architecture| Spec-Server-Architecture]] \ No newline at end of file From b86057e6a4a84a5afaa08b0e00ac163f44a2a08f Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 6 Jul 2011 02:05:43 -0700 Subject: [PATCH 017/178] Created Spec server architecture (markdown) --- Spec-server-architecture.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Spec-server-architecture.md diff --git a/Spec-server-architecture.md b/Spec-server-architecture.md new file mode 100644 index 00000000..2960af9d --- /dev/null +++ b/Spec-server-architecture.md @@ -0,0 +1,3 @@ +## Diagram: Overview of the server architecture ## + +![server_architecture.png](server_architecture.png) \ No newline at end of file From dd7b62f7a1763e21625d059d0309e80f95af97ef Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 6 Jul 2011 02:14:45 -0700 Subject: [PATCH 018/178] Updated Home (markdown) --- Home.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Home.md b/Home.md index 34e6ebc0..4800baac 100644 --- a/Home.md +++ b/Home.md @@ -5,7 +5,8 @@ The official documentation/wiki is located at https://github.com/Eiffel-World/Ei - **Eiffel Web Framework**: Please visit the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) -- See a first [[list of tasks, and a potential roadmap| Tasks-Roadmap]] - See also + - You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]] + - [[list of tasks, and a potential roadmap| Tasks-Roadmap]] - [[General source structure of this project| Source-structure]] - [[Overview of the server side architecture| Spec-Server-Architecture]] \ No newline at end of file From fbbfc784b17c3ffd11a5ae5cc5d72dd583f3cb1b Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 6 Jul 2011 02:22:41 -0700 Subject: [PATCH 019/178] Created Community collaboration (markdown) --- Community-collaboration.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Community-collaboration.md diff --git a/Community-collaboration.md b/Community-collaboration.md new file mode 100644 index 00000000..2c4f551e --- /dev/null +++ b/Community-collaboration.md @@ -0,0 +1,19 @@ +This project is a community project + +## Mailing list ## +- Google group: http://groups.google.com/group/eiffel-web-framework + +## Materials ## +- wiki: github wiki at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/Community-collaboration +- Shared documents: on google docs at http://goo.gl/M8WLP +- source code: git repository at https://github.com/Eiffel-World/Eiffel-Web-Framework + +## Main contributors ## +- **jfiat**: Jocelyn Fiat (Eiffel Software | http://eiffel.com/) +- **jvelilla**: Hector Javier Velilla (Seibo Software Studios | http://http://seibostudios.se/en/) +- **paco**: Paul Cohen (Seibo Software Studios | http://http://seibostudios.se/en/) +- **daro**: Daniel Rodriguez (Seibo Software Studios | http://http://seibostudios.se/en/) + +## You want to participate ## +- You are welcome to contribute (code, test, doc, code review, feedback, suggestion, spread the words ...) +- Feel free to subscribe to the mailing list From 5a4a749c0f7b03ba206fb2205e470ffcffd0dbc8 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 6 Jul 2011 02:24:18 -0700 Subject: [PATCH 020/178] Updated Tasks Roadmap (markdown) --- Tasks-Roadmap.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Tasks-Roadmap.md b/Tasks-Roadmap.md index 9f921e84..69ba8900 100644 --- a/Tasks-Roadmap.md +++ b/Tasks-Roadmap.md @@ -28,11 +28,7 @@ - Persistence chooser * Dynamic update of running system (**daro**) - ## Contributors ## - - **jfiat** = Jocelyn Fiat - - **paco** = Paul Cohen - - **daro** = Daniel Rodriguez - - **jvelilla** = Hector Javier Velilla + - See [[the collaboration page|Community-collaboration]] note: In bold, you see the responsible for each task, but contribution from other is possible as well. \ No newline at end of file From 843a3efe0f60af0430326377e4625f0455bab66a Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 6 Jul 2011 03:45:59 -0700 Subject: [PATCH 021/178] Updated Home (markdown) --- Home.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Home.md b/Home.md index 4800baac..1ed5c245 100644 --- a/Home.md +++ b/Home.md @@ -1,6 +1,6 @@ ## Eiffel-Web-Framework ## -The official documentation/wiki is located at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki , if you are visiting a "clone/fork", please always check the [[original wiki|https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki]]. +The official documentation/wiki is located at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki , if you are visiting a "clone/fork", please always check the original wiki at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki - **Eiffel Web Framework**: Please visit the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) From 398139ee1979b693236ac458ae0f20ae87a1a94e Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 6 Jul 2011 03:47:02 -0700 Subject: [PATCH 022/178] Updated Home (markdown) --- Home.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Home.md b/Home.md index 1ed5c245..8c50451c 100644 --- a/Home.md +++ b/Home.md @@ -1,6 +1,6 @@ ## Eiffel-Web-Framework ## -The official documentation/wiki is located at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki , if you are visiting a "clone/fork", please always check the original wiki at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki +The official documentation/wiki is located at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki , if you are visiting a "clone/fork", please always check the [[official wiki|https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki]]. - **Eiffel Web Framework**: Please visit the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) From b57450d762dce22602e347e99b641fba3ce70c3d Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 6 Jul 2011 03:48:31 -0700 Subject: [PATCH 023/178] Updated Home (markdown) --- Home.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Home.md b/Home.md index 8c50451c..a37146d7 100644 --- a/Home.md +++ b/Home.md @@ -3,7 +3,7 @@ The official documentation/wiki is located at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki , if you are visiting a "clone/fork", please always check the [[official wiki|https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki]]. -- **Eiffel Web Framework**: Please visit the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) +- Mailing list: please visit and subscribe to the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) - See also - You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]] From 36539997cd8a781b031da2185db1a362607345c2 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Thu, 7 Jul 2011 01:24:05 -0700 Subject: [PATCH 024/178] Updated Community collaboration (markdown) --- Community-collaboration.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Community-collaboration.md b/Community-collaboration.md index 2c4f551e..e8cf3f37 100644 --- a/Community-collaboration.md +++ b/Community-collaboration.md @@ -4,9 +4,10 @@ This project is a community project - Google group: http://groups.google.com/group/eiffel-web-framework ## Materials ## -- wiki: github wiki at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/Community-collaboration +- wiki: github wiki at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki - Shared documents: on google docs at http://goo.gl/M8WLP - source code: git repository at https://github.com/Eiffel-World/Eiffel-Web-Framework +- temporary wiki for EWSGI spec at http://eiffel.seibostudios.se/wiki/EWSGI ## Main contributors ## - **jfiat**: Jocelyn Fiat (Eiffel Software | http://eiffel.com/) From 1f385658ed647b690076606e91bf276807da3c05 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Thu, 7 Jul 2011 06:41:47 -0700 Subject: [PATCH 025/178] Updated Source structure (markdown) --- Source-structure.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source-structure.md b/Source-structure.md index 1314e608..b49988ff 100644 --- a/Source-structure.md +++ b/Source-structure.md @@ -4,8 +4,8 @@ - README : quick README to point to the github project - doc/ - doc/wiki : clone of the associated github wiki repository -- example/ -- test/ +- examples/ +- tests/ - library/ - library/ewsgi/ewsgi.ecf - library/ewsgi/ewsgi.ecf @@ -19,9 +19,9 @@ Any library/component (in development mode) should follow the following structur - **library/** : the place to put the source code of the related library/component - **doc/** : notes, documentations, ... - **test/** : standard place to put your tests, if you are using Eiffel Software auto-tests, I would suggest to add a new target into the associated .ecf (instead of building a new .ecf under test/ ) -- **example/** : standard place to put the example +- **examples/** : standard place to put the example - **build/** : a convenient place to compile your project, using this convention, you can setup utilities such as backup to ignore this folder. -- **resource/** : contains pixmap files, .... +- **resources/** : contains pixmap files, .... - **install/** : contains installation scripts for each platform - **data/** : contains eventual data for the related tools From 6cba9a912f14e29075fdce2948696e372e5c323e Mon Sep 17 00:00:00 2001 From: seibo Date: Thu, 7 Jul 2011 15:56:14 -0700 Subject: [PATCH 026/178] Created EWSGI/specification (markdown) --- EWSGI-specification.md | 109 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 EWSGI-specification.md diff --git a/EWSGI-specification.md b/EWSGI-specification.md new file mode 100644 index 00000000..c9c6fb67 --- /dev/null +++ b/EWSGI-specification.md @@ -0,0 +1,109 @@ +The Eiffel Web Server Gateway Interface# +Preface## + +This document specifies a proposed standard interface between web servers and Eiffel web applications or frameworks, to promote web application portability across a variety of web servers. + +Note: This document is based on [PEP 333](http://www.python.org/dev/peps/pep-0333/) -- Python Web Server Gateway Interface v1.0 but adapted to needs and properties of Eiffel. +Rationale and Goals + +The most important goal of EWSGI is to enable an amazingly simple and wonderful programmer experience to the Eiffel developer who wants to write Eiffel server applications for the web! + +Other programming laguages like Java boast a wide variety of web application frameworks. Java's "servlet" API makes it possible for applications written with any Java web application framework to run in any web server that supports the servlet API. Python also boasts many frameworks like Zope, Quixote, Webware, SkunkWeb, PSO, and Twisted Web -- to name just a few. This wide variety of choices was a problem for new Python users, because there was no standard protocol or convention for how webservers were to interact with Python applications and frameworks and this meant that the frameworks only worked with some webservers and not with others. To resolve this the PEP 333 -- Python Web Server Gateway Interface v1.0 was written and subsequently implemented in many webserver environments and in Python frameworks. + +The availability and widespread use of such an API in web servers for Eiffel -- whether those servers are written in Eiffel (e.g. Niño), embed Eiffel in Apache (e.g. mod_eiffel), or invoke Eiffel via a gateway protocol (e.g. CGI, FastCGI, etc.) -- would separate choice of framework from choice of web server, freeing users to choose a pairing that suits them, while freeing server developers as well as developers of higher level web application framworks and tools, like AJC (Alex's Eiffel2JavaScript), to focus on their preferred area of specialization. + +This document, therefore, proposes a simple and universal interface between web servers and Eiffel web applications and frameworks: the Eiffel Web Server Gateway Interface (EWSGI). + +But the mere existence of a EWSGI spec does nothing to address the existing state of servers and frameworks for Eiffel web applications. Server and framework authors and maintainers must actually implement EWSGI for there to be any effect. + +However, since no existing servers or frameworks support EWSGI, there is little immediate reward for an author who implements EWSGI support. Thus, EWSGI must be easy to implement, so that an author's initial investment in the interface can be reasonably low. + +Thus, simplicity of implementation on both the server and framework sides of the interface is absolutely critical to the utility of the EWSGI interface, and is therefore the principal criterion for any design decisions. + +Note, however, that simplicity of implementation for a framework author is not the same thing as ease of use for a web application author. EWSGI presents an absolutely "no frills" interface to the framework author, because bells and whistles like response objects and cookie handling would just get in the way of existing frameworks' handling of these issues. Again, the goal of EWSGI is to facilitate easy interconnection of existing servers and applications or frameworks, not to create a new web framework. +Proof-of-concept and reference implementation ¶ + +We propose a proof-of-concept or reference implementation be done for Apache on Linux and Windows using EiffelWebReloaded and WAMIE. +Specification overview ¶ +The Server/Gateway Side ¶ + +This is the web server side. The server sends the request information in an environment object or structure to the Application/Framework side and expects information on what to return in the form of a response object. +The Application/Framework Side ¶ + +This is the Eiffel application side. Basically one should be able to write: + +class APPLICATION +Inherit + EW_APPLICATION +creation + make - - THIS IS PART OF THE EWSGI SPECIFICATION! +features + execute (env: ENVIRON): RESPONSE is - - THIS IS PART OF THE EWSGI SPECIFICATION! + do + create Result + if env.path_info = ”/hello” then + Result.set_status (Http_ok) + Result.set_header (”Content-Type”, ”text/html; charset=utf-8”) + Result.put_contents (”Hello World”) + else + Result.set_status (Http_not_found) + end + end +end + +Or to register handlers for specific URL paths (or regexp based URL path expressions): + +class APPLICATION +Inherit + EW_APPLICATION +creation + make +redefine + make +features + + make is + do + register_handler (”/hello”, ~hello_world_handler) + -- The default execute feature will dispatch calls to the appropriate handler! + end + + hello_world_handler (env: ENVIRON): RESPONSE is + do + create Result + if env.path_info = ”/hello” then + Result.set_status (Http_ok) + Result.set_header (”Content-Type”, ”text/html; charset=utf-8”) + Result.put_contents (”Hello World”) + else + Result.set_status (Http_not_found) + end + end + end +end + +Specification Details ¶ + +Required information in the ENVIRONMENT class. + +The ENVIRONMENT class is required to provide features for accesing CGI environment variables, as defined by the Common Gateway Interface specification. The following variables must be present. +Variable Description +auth_type: STRING "Basic", "Digest" or some other token. +request_method: STRING The HTTP request method, such as "GET" or "POST". +script_name: STRING The initial portion of the request URL's "path" that corresponds to the application object, so that the application knows its virtual "location". This may be an empty string, if the application corresponds to the "root" of the server. +path_info: STRING The remainder of the request URL's "path", designating the virtual "location" of the request's target within the application. This may be an empty string, if the request URL targets the application root and does not have a trailing slash. +query_string: STRING The portion of the request URL that follows the "?", if any. +content_type: STRING The contents of any Content-Type fields in the HTTP request. May be empty. +content_length: STRING The contents of any Content-Length fields in the HTTP request. May be empty. +server_name, server_port: STRING When combined with script_name and path_info, these variables can be used to complete the URL. Note, however, that HTTP_HOST, if present, should be used in preference to server_name for reconstructing the request URL. See the URL Reconstruction section below for more detail. server_name and server_port can never be empty strings. +server_protocol: STRING The version of the protocol the client used to send the request. Typically this will be something like "HTTP/1.0" or "HTTP/1.1" and may be used by the application to determine how to treat any HTTP request headers. (This variable should probably be called request_protocol, since it denotes the protocol used in the request, and is not necessarily the protocol that will be used in the server's response. However, for compatibility with CGI we have to keep the existing name.) +http_variables: HASH_TABLE [STRING, STRING] Variables corresponding to the client-supplied HTTP request headers (i.e., variables whose names begin with "HTTP_"). The presence or absence of these variables should correspond with the presence or absence of the appropriate HTTP header in the request. + +Required information in the RESPONSE class. +Implementation/Application Notes ¶ + +For an Eiffel system to run it needs to be compiled to a executable program or shared library (.so/.dll). For supporting CGI all that is needed is an executable program, For FCGI and EWSGI we need to compile the Eiffel system to a shared library. +Questions and Answers ¶ +Proposed/Under Discussion ¶ +Acknowledgements ¶ +References ¶ \ No newline at end of file From 831f73b3084742ceea388fc6a9807d426c1d8747 Mon Sep 17 00:00:00 2001 From: seibo Date: Thu, 7 Jul 2011 15:57:14 -0700 Subject: [PATCH 027/178] Updated EWSGI specification (markdown) --- EWSGI-specification.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index c9c6fb67..53d04a80 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -1,5 +1,5 @@ -The Eiffel Web Server Gateway Interface# -Preface## +# The Eiffel Web Server Gateway Interface # +## Preface ## This document specifies a proposed standard interface between web servers and Eiffel web applications or frameworks, to promote web application portability across a variety of web servers. From 13515504c3bde212c374c41d3d197ee458f5f514 Mon Sep 17 00:00:00 2001 From: seibo Date: Thu, 7 Jul 2011 15:58:16 -0700 Subject: [PATCH 028/178] Updated The Eiffel Web Server Gateway Interface (markdown) --- EWSGI-specification.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index 53d04a80..50913066 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -1,5 +1,5 @@ -# The Eiffel Web Server Gateway Interface # -## Preface ## +# The Eiffel Web Server Gateway Interface +## Preface This document specifies a proposed standard interface between web servers and Eiffel web applications or frameworks, to promote web application portability across a variety of web servers. From ab924d35965a8cd157505ca77942f451e6e93c8b Mon Sep 17 00:00:00 2001 From: seibo Date: Thu, 7 Jul 2011 16:11:10 -0700 Subject: [PATCH 029/178] Updated The Eiffel Web Server Gateway Interface (markdown) --- EWSGI-specification.md | 60 ++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index 50913066..8d99ee27 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -4,11 +4,11 @@ This document specifies a proposed standard interface between web servers and Eiffel web applications or frameworks, to promote web application portability across a variety of web servers. Note: This document is based on [PEP 333](http://www.python.org/dev/peps/pep-0333/) -- Python Web Server Gateway Interface v1.0 but adapted to needs and properties of Eiffel. -Rationale and Goals +## Rationale and Goals The most important goal of EWSGI is to enable an amazingly simple and wonderful programmer experience to the Eiffel developer who wants to write Eiffel server applications for the web! -Other programming laguages like Java boast a wide variety of web application frameworks. Java's "servlet" API makes it possible for applications written with any Java web application framework to run in any web server that supports the servlet API. Python also boasts many frameworks like Zope, Quixote, Webware, SkunkWeb, PSO, and Twisted Web -- to name just a few. This wide variety of choices was a problem for new Python users, because there was no standard protocol or convention for how webservers were to interact with Python applications and frameworks and this meant that the frameworks only worked with some webservers and not with others. To resolve this the PEP 333 -- Python Web Server Gateway Interface v1.0 was written and subsequently implemented in many webserver environments and in Python frameworks. +Other programming laguages like Java boast a wide variety of web application frameworks. Java's "servlet" API makes it possible for applications written with any Java web application framework to run in any web server that supports the servlet API. Python also boasts many frameworks like Zope, Quixote, Webware, SkunkWeb, PSO, and Twisted Web -- to name just a few. This wide variety of choices was a problem for new Python users, because there was no standard protocol or convention for how webservers were to interact with Python applications and frameworks and this meant that the frameworks only worked with some webservers and not with others. To resolve this the [PEP 333](http://www.python.org/dev/peps/pep-0333/) -- Python Web Server Gateway Interface v1.0 was written and subsequently implemented in many webserver environments and in Python frameworks. The availability and widespread use of such an API in web servers for Eiffel -- whether those servers are written in Eiffel (e.g. Niño), embed Eiffel in Apache (e.g. mod_eiffel), or invoke Eiffel via a gateway protocol (e.g. CGI, FastCGI, etc.) -- would separate choice of framework from choice of web server, freeing users to choose a pairing that suits them, while freeing server developers as well as developers of higher level web application framworks and tools, like AJC (Alex's Eiffel2JavaScript), to focus on their preferred area of specialization. @@ -21,25 +21,29 @@ However, since no existing servers or frameworks support EWSGI, there is little Thus, simplicity of implementation on both the server and framework sides of the interface is absolutely critical to the utility of the EWSGI interface, and is therefore the principal criterion for any design decisions. Note, however, that simplicity of implementation for a framework author is not the same thing as ease of use for a web application author. EWSGI presents an absolutely "no frills" interface to the framework author, because bells and whistles like response objects and cookie handling would just get in the way of existing frameworks' handling of these issues. Again, the goal of EWSGI is to facilitate easy interconnection of existing servers and applications or frameworks, not to create a new web framework. -Proof-of-concept and reference implementation ¶ + +## Proof-of-concept and reference implementation We propose a proof-of-concept or reference implementation be done for Apache on Linux and Windows using EiffelWebReloaded and WAMIE. -Specification overview ¶ -The Server/Gateway Side ¶ + +## Specification overview + +## The Server/Gateway Side This is the web server side. The server sends the request information in an environment object or structure to the Application/Framework side and expects information on what to return in the form of a response object. -The Application/Framework Side ¶ + +## The Application/Framework Side This is the Eiffel application side. Basically one should be able to write: -class APPLICATION -Inherit - EW_APPLICATION -creation - make - - THIS IS PART OF THE EWSGI SPECIFICATION! -features - execute (env: ENVIRON): RESPONSE is - - THIS IS PART OF THE EWSGI SPECIFICATION! - do + class APPLICATION + inherit + EW_APPLICATION + creation + make - - THIS IS PART OF THE EWSGI SPECIFICATION! + features + execute (env: ENVIRON): RESPONSE is - - THIS IS PART OF THE EWSGI SPECIFICATION! + do create Result if env.path_info = ”/hello” then Result.set_status (Http_ok) @@ -48,27 +52,27 @@ features else Result.set_status (Http_not_found) end - end -end + end + end Or to register handlers for specific URL paths (or regexp based URL path expressions): -class APPLICATION -Inherit - EW_APPLICATION -creation - make -redefine - make -features + class APPLICATION + inherit + EW_APPLICATION + creation + make + redefine + make + features - make is + make is do register_handler (”/hello”, ~hello_world_handler) -- The default execute feature will dispatch calls to the appropriate handler! end - hello_world_handler (env: ENVIRON): RESPONSE is + hello_world_handler (env: ENVIRON): RESPONSE is do create Result if env.path_info = ”/hello” then @@ -79,8 +83,8 @@ features Result.set_status (Http_not_found) end end - end -end + end + end Specification Details ¶ From 6309bbfa52f9fd7f90ef494b5a0eaffc7f28a939 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Fri, 8 Jul 2011 05:39:44 -0700 Subject: [PATCH 030/178] Updated The Eiffel Web Server Gateway Interface (markdown) --- EWSGI-specification.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index 8d99ee27..079166ce 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -1,3 +1,5 @@ +**WARNING** **THIS PAGE IS IN PROGRESS, AS IT IS NOW, IT NEEDS UPDATE SINCE IT DOES NOT REFLECT THE FUTURE INTERFACE** + # The Eiffel Web Server Gateway Interface ## Preface From d5288a4ebebcaa405215674b5ff469a00a76372b Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 12 Jul 2011 10:33:14 -0700 Subject: [PATCH 031/178] Updated Home (markdown) --- Home.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Home.md b/Home.md index a37146d7..5e6c68cf 100644 --- a/Home.md +++ b/Home.md @@ -9,4 +9,5 @@ The official documentation/wiki is located at https://github.com/Eiffel-World/Ei - You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]] - [[list of tasks, and a potential roadmap| Tasks-Roadmap]] - [[General source structure of this project| Source-structure]] - - [[Overview of the server side architecture| Spec-Server-Architecture]] \ No newline at end of file + - [[Overview of the server side architecture| Spec-Server-Architecture]] + - This project is also a collection of [[Libraries]] related to the Web \ No newline at end of file From 13993197d365b74d096c49b1f891afabf154e8d5 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 12 Jul 2011 10:39:15 -0700 Subject: [PATCH 032/178] Created Libraries (markdown) --- Libraries.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 Libraries.md diff --git a/Libraries.md b/Libraries.md new file mode 100644 index 00000000..280a4961 --- /dev/null +++ b/Libraries.md @@ -0,0 +1,10 @@ +The libraries which are currently part of the Eiffel Web Framework +- [[Library-EWSGI]]: Eiffel Web Server Gateway Interface (prefix GW_ for **G**ate**W**ay) +- [[Library-libFCGI]]: Eiffel wrapper of libfcgi SDK (http://www.fastcgi.com/devkit/libfcgi/) +- [[Library-encoder]]: simple encoder for base64, url-encode, xml entities +- [[Library-error]]: simple framework to handle error in EWSGI and related +- [[Library-http]]: utility classes to handle HTTP protocol, status, ... + +The libraries which are needed but not (yet) in the collection of libraries +- [[Library-EiffelWebNino]]: Eiffel Web Server written in Eiffel +- [[Library-JSON]]: JSON format parser and converter \ No newline at end of file From d409eac9d625d70b1ba17ad0b44a5d179109b6bf Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 12 Jul 2011 10:41:22 -0700 Subject: [PATCH 033/178] Updated Libraries (markdown) --- Libraries.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Libraries.md b/Libraries.md index 280a4961..015d5e20 100644 --- a/Libraries.md +++ b/Libraries.md @@ -1,10 +1,14 @@ -The libraries which are currently part of the Eiffel Web Framework -- [[Library-EWSGI]]: Eiffel Web Server Gateway Interface (prefix GW_ for **G**ate**W**ay) -- [[Library-libFCGI]]: Eiffel wrapper of libfcgi SDK (http://www.fastcgi.com/devkit/libfcgi/) -- [[Library-encoder]]: simple encoder for base64, url-encode, xml entities -- [[Library-error]]: simple framework to handle error in EWSGI and related -- [[Library-http]]: utility classes to handle HTTP protocol, status, ... +## libraries currently part of the Eiffel Web Framework ## +* [[Library-EWSGI]]: Eiffel Web Server Gateway Interface (prefix GW_ for **G**ate**W**ay) +* [[Library-libFCGI]]: Eiffel wrapper of libfcgi SDK (http://www.fastcgi.com/devkit/libfcgi/) +* [[Library-encoder]]: simple encoder for base64, url-encode, xml entities +* [[Library-error]]: simple framework to handle error in EWSGI and related +* [[Library-http]]: utility classes to handle HTTP protocol, status, ... -The libraries which are needed but not (yet) in the collection of libraries -- [[Library-EiffelWebNino]]: Eiffel Web Server written in Eiffel -- [[Library-JSON]]: JSON format parser and converter \ No newline at end of file +## libraries needed but not (yet) in the current framework ## +* [[Library-EiffelWebNino]]: Eiffel Web Server written in Eiffel +* [[Library-JSON]]: JSON format parser and converter + +## libraries that could be included, or or used ## +* eMIME +* \ No newline at end of file From 4880d23846206eb8ec45292814d3283cb07ef4ab Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 12 Jul 2011 10:42:09 -0700 Subject: [PATCH 034/178] Updated Libraries (markdown) --- Libraries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries.md b/Libraries.md index 015d5e20..377865ab 100644 --- a/Libraries.md +++ b/Libraries.md @@ -10,5 +10,5 @@ * [[Library-JSON]]: JSON format parser and converter ## libraries that could be included, or or used ## -* eMIME +* eMIME: MIME parser, and encoder ... * \ No newline at end of file From 838982906762225f41dce22de61b3efeae0f2150 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 12 Jul 2011 10:42:23 -0700 Subject: [PATCH 035/178] Updated Libraries (markdown) --- Libraries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries.md b/Libraries.md index 377865ab..08aa53fc 100644 --- a/Libraries.md +++ b/Libraries.md @@ -11,4 +11,4 @@ ## libraries that could be included, or or used ## * eMIME: MIME parser, and encoder ... -* \ No newline at end of file +* ... \ No newline at end of file From cc7e54a19b4cd0ad0a890ef029ed5b7820b24ab8 Mon Sep 17 00:00:00 2001 From: seibo Date: Tue, 12 Jul 2011 14:34:05 -0700 Subject: [PATCH 036/178] Updated EWSGI specification (markdown) --- EWSGI-specification.md | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index 079166ce..0aa33cd8 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -26,9 +26,27 @@ Note, however, that simplicity of implementation for a framework author is not t ## Proof-of-concept and reference implementation -We propose a proof-of-concept or reference implementation be done for Apache on Linux and Windows using EiffelWebReloaded and WAMIE. +We propose a proof-of-concept or reference implementation be done with: -## Specification overview +* CGI +* FCGI +* Nino. A simple Web server written in Eiffel by Javier Velilla. +* mod_ewsgi. Apache module on Linux and Windows using Wamie. + +The reference implementation should enable a user to write an EWSGI "Hello World" application: + +1. Using just 1 Eiffel class of ~10 lines of code. +1. And easily switch deployment method (CGI, FCGI, Nino or mod_ewsgi). + +A reference implementation is being worked on by Jocelyn Fiat (Eiffel Software), Javier Velilla (independent), Daniel Rodríguez (Seibo) and Paul Cohen (Seibo). The reference implementation consists of + +1. EWSGI core library: [Eiffel-WebFramework](https://github.com/Eiffel-World/Eiffel-Web-Framework). +1. eJSON library: [eJSON](http://ejson.origo.ethz.ch/). +1. Nino Eiffel Web server: [Nino](http://code.google.com/p/webeiffel/source/browse/#svn%2Ftrunk%2Feiffelwebnino). +1. mod_ewsgi module. Based on [Wamie](http://eiffel.seibostudios.se/wiki/Wamie). +1. SOS. Simple Object Storage - a simple Eiffel persistance mechanism. + +# Specification overview ## The Server/Gateway Side @@ -82,13 +100,13 @@ Or to register handlers for specific URL paths (or regexp based URL path express Result.set_header (”Content-Type”, ”text/html; charset=utf-8”) Result.put_contents (”Hello World”) else - Result.set_status (Http_not_found) + Result.set_status (Http_notund) end end - end + e ¶nd end -Specification Details ¶ +## Specification Details Required information in the ENVIRONMENT class. From 4904aba3601d1721a521cf1a228b4d41e5962d23 Mon Sep 17 00:00:00 2001 From: seibo Date: Tue, 12 Jul 2011 15:48:53 -0700 Subject: [PATCH 037/178] Updated EWSGI specification (markdown) --- EWSGI-specification.md | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index 0aa33cd8..e4f10d1a 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -103,31 +103,46 @@ Or to register handlers for specific URL paths (or regexp based URL path express Result.set_status (Http_notund) end end - e ¶nd + end end ## Specification Details -Required information in the ENVIRONMENT class. +Required information in the **ENVIRONMENT** class. + +The **ENVIRONMENT** class is required to provide features for accesing CGI environment variables, as defined by the [Common Gateway Interface specification](http://ken.coar.org/cgi/draft-coar-cgi-v11-03.txt). The following variables must be present. -The ENVIRONMENT class is required to provide features for accesing CGI environment variables, as defined by the Common Gateway Interface specification. The following variables must be present. Variable Description + auth_type: STRING "Basic", "Digest" or some other token. + request_method: STRING The HTTP request method, such as "GET" or "POST". + script_name: STRING The initial portion of the request URL's "path" that corresponds to the application object, so that the application knows its virtual "location". This may be an empty string, if the application corresponds to the "root" of the server. + path_info: STRING The remainder of the request URL's "path", designating the virtual "location" of the request's target within the application. This may be an empty string, if the request URL targets the application root and does not have a trailing slash. + query_string: STRING The portion of the request URL that follows the "?", if any. + content_type: STRING The contents of any Content-Type fields in the HTTP request. May be empty. + content_length: STRING The contents of any Content-Length fields in the HTTP request. May be empty. + server_name, server_port: STRING When combined with script_name and path_info, these variables can be used to complete the URL. Note, however, that HTTP_HOST, if present, should be used in preference to server_name for reconstructing the request URL. See the URL Reconstruction section below for more detail. server_name and server_port can never be empty strings. + server_protocol: STRING The version of the protocol the client used to send the request. Typically this will be something like "HTTP/1.0" or "HTTP/1.1" and may be used by the application to determine how to treat any HTTP request headers. (This variable should probably be called request_protocol, since it denotes the protocol used in the request, and is not necessarily the protocol that will be used in the server's response. However, for compatibility with CGI we have to keep the existing name.) + http_variables: HASH_TABLE [STRING, STRING] Variables corresponding to the client-supplied HTTP request headers (i.e., variables whose names begin with "HTTP_"). The presence or absence of these variables should correspond with the presence or absence of the appropriate HTTP header in the request. Required information in the RESPONSE class. -Implementation/Application Notes ¶ +## Implementation/Application Notes For an Eiffel system to run it needs to be compiled to a executable program or shared library (.so/.dll). For supporting CGI all that is needed is an executable program, For FCGI and EWSGI we need to compile the Eiffel system to a shared library. -Questions and Answers ¶ -Proposed/Under Discussion ¶ -Acknowledgements ¶ -References ¶ \ No newline at end of file + +## Questions and Answers + +## Proposed/Under Discussion + +## Acknowledgements + +## References \ No newline at end of file From e63553555da2886b8e4442ba9a7b28cde6455fca Mon Sep 17 00:00:00 2001 From: seibo Date: Tue, 12 Jul 2011 15:57:54 -0700 Subject: [PATCH 038/178] Updated EWSGI specification (markdown) --- EWSGI-specification.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index e4f10d1a..a2b1e608 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -56,24 +56,24 @@ This is the web server side. The server sends the request information in an envi This is the Eiffel application side. Basically one should be able to write: - class APPLICATION - inherit - EW_APPLICATION - creation - make - - THIS IS PART OF THE EWSGI SPECIFICATION! - features - execute (env: ENVIRON): RESPONSE is - - THIS IS PART OF THE EWSGI SPECIFICATION! - do - create Result - if env.path_info = ”/hello” then - Result.set_status (Http_ok) - Result.set_header (”Content-Type”, ”text/html; charset=utf-8”) - Result.put_contents (”Hello World”) - else - Result.set_status (Http_not_found) - end - end - end + class APPLICATION + inherit + EW_APPLICATION + creation + make - - THIS IS PART OF THE EWSGI SPECIFICATION! + features + execute (env: ENVIRON): RESPONSE is - - THIS IS PART OF THE EWSGI SPECIFICATION! + do + create Result + if env.path_info = ”/hello” then + Result.set_status (Http_ok) + Result.set_header (”Content-Type”, ”text/html; charset=utf-8”) + Result.put_contents (”Hello World”) + else + Result.set_status (Http_not_found) + end + end + end` Or to register handlers for specific URL paths (or regexp based URL path expressions): From e1120040bbe843cc4d67e14b0b52fe580a466d6b Mon Sep 17 00:00:00 2001 From: seibo Date: Tue, 12 Jul 2011 16:02:30 -0700 Subject: [PATCH 039/178] Updated EWSGI specification (markdown) --- EWSGI-specification.md | 51 ++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index a2b1e608..dd9ec204 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -73,37 +73,34 @@ This is the Eiffel application side. Basically one should be able to write: Result.set_status (Http_not_found) end end - end` + end Or to register handlers for specific URL paths (or regexp based URL path expressions): class APPLICATION - inherit - EW_APPLICATION - creation - make - redefine - make - features - - make is - do - register_handler (”/hello”, ~hello_world_handler) - -- The default execute feature will dispatch calls to the appropriate handler! - end - - hello_world_handler (env: ENVIRON): RESPONSE is - do - create Result - if env.path_info = ”/hello” then - Result.set_status (Http_ok) - Result.set_header (”Content-Type”, ”text/html; charset=utf-8”) - Result.put_contents (”Hello World”) - else - Result.set_status (Http_notund) - end - end - end + inherit + EW_APPLICATION + creation + make + redefine + make + feature + make is + do + register_handler (”/hello”, ~hello_world_handler) + -- The default execute feature will dispatch calls to the appropriate handler! + end + hello_world_handler (env: ENVIRON): RESPONSE is + do + create Result + if env.path_info = ”/hello” then + Result.set_status (Http_ok) + Result.set_header (”Content-Type”, ”text/html; charset=utf-8”) + Result.put_contents (”Hello World”) + else + Result.set_status (Http_notund) + end + end end ## Specification Details From c7f4f45f5eab34092d633f9e9bca52a8e9f33a90 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Thu, 21 Jul 2011 10:01:04 -0700 Subject: [PATCH 040/178] Updated Libraries (markdown) --- Libraries.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Libraries.md b/Libraries.md index 08aa53fc..6b72e4d0 100644 --- a/Libraries.md +++ b/Libraries.md @@ -4,6 +4,7 @@ * [[Library-encoder]]: simple encoder for base64, url-encode, xml entities * [[Library-error]]: simple framework to handle error in EWSGI and related * [[Library-http]]: utility classes to handle HTTP protocol, status, ... +* [[Library-uri-template]]: URI Template parser and expander (follow draft spec 0.5) ## libraries needed but not (yet) in the current framework ## * [[Library-EiffelWebNino]]: Eiffel Web Server written in Eiffel From 7680d071f1807e0c3cf983a23f778fdb9ccf7b31 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Fri, 29 Jul 2011 06:15:51 -0700 Subject: [PATCH 041/178] Updated Community collaboration (markdown) --- Community-collaboration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Community-collaboration.md b/Community-collaboration.md index e8cf3f37..58098906 100644 --- a/Community-collaboration.md +++ b/Community-collaboration.md @@ -7,7 +7,7 @@ This project is a community project - wiki: github wiki at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki - Shared documents: on google docs at http://goo.gl/M8WLP - source code: git repository at https://github.com/Eiffel-World/Eiffel-Web-Framework -- temporary wiki for EWSGI spec at http://eiffel.seibostudios.se/wiki/EWSGI +- Proposal from Paul Cohen for a EWSGI spec at http://eiffel.seibostudios.se/wiki/EWSGI ## Main contributors ## - **jfiat**: Jocelyn Fiat (Eiffel Software | http://eiffel.com/) From b869eb73331894034129ec7ab6102ceaba936747 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 1 Aug 2011 00:36:52 -0700 Subject: [PATCH 042/178] Updated Home (markdown) --- Home.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Home.md b/Home.md index 5e6c68cf..db832b6a 100644 --- a/Home.md +++ b/Home.md @@ -9,5 +9,6 @@ The official documentation/wiki is located at https://github.com/Eiffel-World/Ei - You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]] - [[list of tasks, and a potential roadmap| Tasks-Roadmap]] - [[General source structure of this project| Source-structure]] + - [[EWSGI specification| EWSGI-specification]] - [[Overview of the server side architecture| Spec-Server-Architecture]] - This project is also a collection of [[Libraries]] related to the Web \ No newline at end of file From a2a1f89299a9fd1ff3078052e4c7917c329d27ed Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 1 Aug 2011 01:19:54 -0700 Subject: [PATCH 043/178] Updated EWSGI specification (markdown) --- EWSGI-specification.md | 126 +++-------------------------------------- 1 file changed, 8 insertions(+), 118 deletions(-) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index dd9ec204..d63c375d 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -2,140 +2,30 @@ # The Eiffel Web Server Gateway Interface ## Preface +This specification is a proposition based on recent discussion on the mailing list. +This is work in progress, so far nothing had been decided. +You can find another proposal at http://eiffel.seibostudios.se/wiki/EWSGI , it has common background and goal, however still differ on specific parts. +The main goal for now is to unified those 2 specifications. -This document specifies a proposed standard interface between web servers and Eiffel web applications or frameworks, to promote web application portability across a variety of web servers. +--- +Note the following is work in progress, and reflect a specification proposal, rather than the final specification. +2011-08-01 +--- -Note: This document is based on [PEP 333](http://www.python.org/dev/peps/pep-0333/) -- Python Web Server Gateway Interface v1.0 but adapted to needs and properties of Eiffel. -## Rationale and Goals -The most important goal of EWSGI is to enable an amazingly simple and wonderful programmer experience to the Eiffel developer who wants to write Eiffel server applications for the web! - -Other programming laguages like Java boast a wide variety of web application frameworks. Java's "servlet" API makes it possible for applications written with any Java web application framework to run in any web server that supports the servlet API. Python also boasts many frameworks like Zope, Quixote, Webware, SkunkWeb, PSO, and Twisted Web -- to name just a few. This wide variety of choices was a problem for new Python users, because there was no standard protocol or convention for how webservers were to interact with Python applications and frameworks and this meant that the frameworks only worked with some webservers and not with others. To resolve this the [PEP 333](http://www.python.org/dev/peps/pep-0333/) -- Python Web Server Gateway Interface v1.0 was written and subsequently implemented in many webserver environments and in Python frameworks. - -The availability and widespread use of such an API in web servers for Eiffel -- whether those servers are written in Eiffel (e.g. Niño), embed Eiffel in Apache (e.g. mod_eiffel), or invoke Eiffel via a gateway protocol (e.g. CGI, FastCGI, etc.) -- would separate choice of framework from choice of web server, freeing users to choose a pairing that suits them, while freeing server developers as well as developers of higher level web application framworks and tools, like AJC (Alex's Eiffel2JavaScript), to focus on their preferred area of specialization. - -This document, therefore, proposes a simple and universal interface between web servers and Eiffel web applications and frameworks: the Eiffel Web Server Gateway Interface (EWSGI). - -But the mere existence of a EWSGI spec does nothing to address the existing state of servers and frameworks for Eiffel web applications. Server and framework authors and maintainers must actually implement EWSGI for there to be any effect. - -However, since no existing servers or frameworks support EWSGI, there is little immediate reward for an author who implements EWSGI support. Thus, EWSGI must be easy to implement, so that an author's initial investment in the interface can be reasonably low. - -Thus, simplicity of implementation on both the server and framework sides of the interface is absolutely critical to the utility of the EWSGI interface, and is therefore the principal criterion for any design decisions. - -Note, however, that simplicity of implementation for a framework author is not the same thing as ease of use for a web application author. EWSGI presents an absolutely "no frills" interface to the framework author, because bells and whistles like response objects and cookie handling would just get in the way of existing frameworks' handling of these issues. Again, the goal of EWSGI is to facilitate easy interconnection of existing servers and applications or frameworks, not to create a new web framework. ## Proof-of-concept and reference implementation -We propose a proof-of-concept or reference implementation be done with: - -* CGI -* FCGI -* Nino. A simple Web server written in Eiffel by Javier Velilla. -* mod_ewsgi. Apache module on Linux and Windows using Wamie. - -The reference implementation should enable a user to write an EWSGI "Hello World" application: - -1. Using just 1 Eiffel class of ~10 lines of code. -1. And easily switch deployment method (CGI, FCGI, Nino or mod_ewsgi). - -A reference implementation is being worked on by Jocelyn Fiat (Eiffel Software), Javier Velilla (independent), Daniel Rodríguez (Seibo) and Paul Cohen (Seibo). The reference implementation consists of - -1. EWSGI core library: [Eiffel-WebFramework](https://github.com/Eiffel-World/Eiffel-Web-Framework). -1. eJSON library: [eJSON](http://ejson.origo.ethz.ch/). -1. Nino Eiffel Web server: [Nino](http://code.google.com/p/webeiffel/source/browse/#svn%2Ftrunk%2Feiffelwebnino). -1. mod_ewsgi module. Based on [Wamie](http://eiffel.seibostudios.se/wiki/Wamie). -1. SOS. Simple Object Storage - a simple Eiffel persistance mechanism. - # Specification overview ## The Server/Gateway Side -This is the web server side. The server sends the request information in an environment object or structure to the Application/Framework side and expects information on what to return in the form of a response object. - ## The Application/Framework Side -This is the Eiffel application side. Basically one should be able to write: - - class APPLICATION - inherit - EW_APPLICATION - creation - make - - THIS IS PART OF THE EWSGI SPECIFICATION! - features - execute (env: ENVIRON): RESPONSE is - - THIS IS PART OF THE EWSGI SPECIFICATION! - do - create Result - if env.path_info = ”/hello” then - Result.set_status (Http_ok) - Result.set_header (”Content-Type”, ”text/html; charset=utf-8”) - Result.put_contents (”Hello World”) - else - Result.set_status (Http_not_found) - end - end - end - -Or to register handlers for specific URL paths (or regexp based URL path expressions): - - class APPLICATION - inherit - EW_APPLICATION - creation - make - redefine - make - feature - make is - do - register_handler (”/hello”, ~hello_world_handler) - -- The default execute feature will dispatch calls to the appropriate handler! - end - hello_world_handler (env: ENVIRON): RESPONSE is - do - create Result - if env.path_info = ”/hello” then - Result.set_status (Http_ok) - Result.set_header (”Content-Type”, ”text/html; charset=utf-8”) - Result.put_contents (”Hello World”) - else - Result.set_status (Http_notund) - end - end - end - ## Specification Details -Required information in the **ENVIRONMENT** class. - -The **ENVIRONMENT** class is required to provide features for accesing CGI environment variables, as defined by the [Common Gateway Interface specification](http://ken.coar.org/cgi/draft-coar-cgi-v11-03.txt). The following variables must be present. - -Variable Description - -auth_type: STRING "Basic", "Digest" or some other token. - -request_method: STRING The HTTP request method, such as "GET" or "POST". - -script_name: STRING The initial portion of the request URL's "path" that corresponds to the application object, so that the application knows its virtual "location". This may be an empty string, if the application corresponds to the "root" of the server. - -path_info: STRING The remainder of the request URL's "path", designating the virtual "location" of the request's target within the application. This may be an empty string, if the request URL targets the application root and does not have a trailing slash. - -query_string: STRING The portion of the request URL that follows the "?", if any. - -content_type: STRING The contents of any Content-Type fields in the HTTP request. May be empty. - -content_length: STRING The contents of any Content-Length fields in the HTTP request. May be empty. - -server_name, server_port: STRING When combined with script_name and path_info, these variables can be used to complete the URL. Note, however, that HTTP_HOST, if present, should be used in preference to server_name for reconstructing the request URL. See the URL Reconstruction section below for more detail. server_name and server_port can never be empty strings. - -server_protocol: STRING The version of the protocol the client used to send the request. Typically this will be something like "HTTP/1.0" or "HTTP/1.1" and may be used by the application to determine how to treat any HTTP request headers. (This variable should probably be called request_protocol, since it denotes the protocol used in the request, and is not necessarily the protocol that will be used in the server's response. However, for compatibility with CGI we have to keep the existing name.) - -http_variables: HASH_TABLE [STRING, STRING] Variables corresponding to the client-supplied HTTP request headers (i.e., variables whose names begin with "HTTP_"). The presence or absence of these variables should correspond with the presence or absence of the appropriate HTTP header in the request. - -Required information in the RESPONSE class. ## Implementation/Application Notes -For an Eiffel system to run it needs to be compiled to a executable program or shared library (.so/.dll). For supporting CGI all that is needed is an executable program, For FCGI and EWSGI we need to compile the Eiffel system to a shared library. - ## Questions and Answers ## Proposed/Under Discussion From 01944508925a924fdc6a082eb640a92650123b19 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 00:21:53 -0700 Subject: [PATCH 044/178] Updated EWSGI specification (markdown) --- EWSGI-specification.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index d63c375d..b35a45f6 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -11,8 +11,8 @@ The main goal for now is to unified those 2 specifications. Note the following is work in progress, and reflect a specification proposal, rather than the final specification. 2011-08-01 --- - - +For now, the specification from EWF is done in Eiffel interface +please see: https://github.com/Eiffel-World/Eiffel-Web-Framework/tree/master/library/server/ewsgi/specification ## Proof-of-concept and reference implementation From cefc95e56f56e2ae7a8d09732642fd6f7156a11a Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 01:02:01 -0700 Subject: [PATCH 045/178] added current eiffel interfaces for APPLICATION, REQUEST and RESPONSE_BUFFER --- EWSGI-specification.md | 271 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index b35a45f6..e771ef4c 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -14,6 +14,277 @@ Note the following is work in progress, and reflect a specification proposal, ra For now, the specification from EWF is done in Eiffel interface please see: https://github.com/Eiffel-World/Eiffel-Web-Framework/tree/master/library/server/ewsgi/specification +EWSGI_APPLICATION + + deferred class + EWSGI_APPLICATION + + feature {NONE} -- Execution + + execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER) + -- Execute the request + -- See `req.input' for input stream + -- `req.environment' for the Gateway environment + -- and `res' for the output buffer + require + res_status_unset: not res.status_is_set + deferred + ensure + res_status_set: res.status_is_set + res_committed: res.message_committed + end + + end + +EWSGI_REQUEST + + deferred class + EWSGI_REQUEST + feature -- Access: Input + + input: EWSGI_INPUT_STREAM + -- Server input channel + deferred + end + + feature -- Access: extra values + + request_time: detachable DATE_TIME + -- Request time (UTC) + deferred + end + + feature -- Access: environment variables + + environment: EWSGI_ENVIRONMENT + -- Environment variables + deferred + end + + environment_variable (a_name: STRING_8): detachable STRING_8 + -- Environment variable related to `a_name' + require + a_name_valid: a_name /= Void and then not a_name.is_empty + deferred + end + + feature -- Access: execution variables + + execution_variables: EWSGI_VARIABLES [STRING_32] + -- Execution variables set by the application + deferred + end + + execution_variable (a_name: STRING_8): detachable STRING_32 + -- Execution variable related to `a_name' + require + a_name_valid: a_name /= Void and then not a_name.is_empty + deferred + end + + feature -- URL Parameters + + parameters: EWSGI_VARIABLES [STRING_32] + -- Variables extracted from QUERY_STRING + deferred + end + + parameter (a_name: STRING_8): detachable STRING_32 + -- Parameter for name `n'. + require + a_name_valid: a_name /= Void and then not a_name.is_empty + deferred + end + + feature -- Form fields and related + + form_fields: EWSGI_VARIABLES [STRING_32] + -- Variables sent by POST request + deferred + end + + form_field (a_name: STRING_8): detachable STRING_32 + -- Field for name `a_name'. + require + a_name_valid: a_name /= Void and then not a_name.is_empty + deferred + end + + uploaded_files: HASH_TABLE [EWSGI_UPLOADED_FILE_DATA, STRING_8] + -- Table of uploaded files information + deferred + end + + feature -- Cookies + + cookies_variables: HASH_TABLE [STRING_8, STRING_8] + -- Expanded cookies variable + deferred + end + + cookies_variable (a_name: STRING_8): detachable STRING_8 + -- Field for name `a_name'. + require + a_name_valid: a_name /= Void and then not a_name.is_empty + deferred + end + + cookies: HASH_TABLE [EWSGI_COOKIE, STRING_8] + -- Cookies Information + deferred + end + + feature -- Access: global variable + + variables: HASH_TABLE [STRING_32, STRING_32] + -- Table containing all the various variables + -- Warning: this is computed each time, if you change the content of other containers + -- this won't update this Result's content, unless you query it again + deferred + end + + variable (a_name: STRING_8): detachable STRING_32 + -- Variable named `a_name' from any of the variables container + -- and following a specific order + -- execution, environment, get, post, cookies + require + a_name_valid: a_name /= Void and then not a_name.is_empty + deferred + end + + feature -- Uploaded File Handling + + is_uploaded_file (a_filename: STRING_8): BOOLEAN + -- Is `a_filename' a file uploaded via HTTP POST + deferred + end + + feature -- URL Utility + + absolute_script_url (a_path: STRING_8): STRING_8 + -- Absolute Url for the script if any, extended by `a_path' + deferred + end + + script_url (a_path: STRING_8): STRING_8 + -- Url relative to script name if any, extended by `a_path' + require + a_path_attached: a_path /= Void + deferred + end + + end + +EWSGI_RESPONSE_BUFFER + + deferred class + EWSGI_RESPONSE_BUFFER + + feature {EWSGI_APPLICATION} -- Commit + + commit + -- Commit the current response + deferred + ensure + status_is_set: status_is_set + header_committed: header_committed + message_committed: message_committed + end + + feature -- Status report + + header_committed: BOOLEAN + -- Header committed? + deferred + end + + message_committed: BOOLEAN + -- Message committed? + deferred + end + + message_writable: BOOLEAN + -- Can message be written? + deferred + end + + feature {NONE} -- Core output operation + + write (s: STRING_8) + -- Send the string `s' + -- this can be used for header and body + deferred + end + + feature -- Status setting + + status_is_set: BOOLEAN + -- Is status set? + deferred + end + + set_status_code (a_code: INTEGER_32) + -- Set response status code + -- Should be done before sending any data back to the client + require + status_not_set: not status_is_set + header_not_committed: not header_committed + deferred + ensure + status_code_set: status_code = a_code + status_set: status_is_set + end + + status_code: INTEGER_32 + -- Response status + deferred + end + + feature -- Output operation + + flush + -- Flush if it makes sense + deferred + end + + write_string (s: STRING_8) + -- Send the string `s' + require + message_writable: message_writable + deferred + end + + write_substring (s: STRING_8; a_begin_index, a_end_index: INTEGER_32) + -- Send the substring `s[a_begin_index:a_end_index]' + require + message_writable: message_writable + deferred + end + + write_file_content (fn: STRING_8) + -- Send the content of file `fn' + require + message_writable: message_writable + deferred + end + + feature -- Header output operation + + write_header (a_status_code: INTEGER_32; a_headers: detachable ARRAY [TUPLE [key: STRING_8; value: STRING_8]]) + -- Send headers with status `a_status', and headers from `a_headers' + require + status_not_set: not status_is_set + header_not_committed: not header_committed + deferred + ensure + header_committed: header_committed + status_set: status_is_set + end + + end + + + ## Proof-of-concept and reference implementation # Specification overview From 4ab99dcd4a76287846b74c9e5bfa05d3a8918cf5 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 02:52:31 -0700 Subject: [PATCH 046/178] Created EWSGI specification: difference in main proposals (markdown) --- ...ification:-difference-in-main-proposals.md | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 EWSGI-specification:-difference-in-main-proposals.md diff --git a/EWSGI-specification:-difference-in-main-proposals.md b/EWSGI-specification:-difference-in-main-proposals.md new file mode 100644 index 00000000..a2c2f092 --- /dev/null +++ b/EWSGI-specification:-difference-in-main-proposals.md @@ -0,0 +1,99 @@ +Currently the **design of the EWSGI** is not going very fast, mainly due to conflicts for the core design. + +Let's try to summary today's **points of conflict** between Paul's proposal, and Jocelyn's proposal. +Since Paul put the specification on the wiki from Seibo Solution Studio, +and Jocelyn is implementing the proposal withing the current Eiffel Web Framework. +(If other proposals are provided, we'll compare them to those 2 existing proposals.) + +Let's name the **Seibo-EWSGI** proposal and the **EWF-EWSGI** proposal. + +Of course, **the goal is to have only one specification**, but it is good to have more than one proposal. So that we really try to specify the best EWSGI as possible. + +Let's remind that EWSGI is meant to be a specification, and we are looking at **Specification-Compliance** for the future implementation (so this is mainly about class names, and feature signatures. I.e the Eiffel system interface). + +_Note_: to make the code shorter, we will not always include the prefix EWSGI_ to the class name. +_Note2_: we will use the term of "user" for the developer using the EWSGI specification and/or implementation(s) + +## General goal ## +At first, the main difference between Seibo-EWSGI and EWF-EWSGI is a tiny nuance on the general goal. +_Seibo-EWSGI_: get web application portability across a variety of web servers. +_EWF-EWSGI_: get web application portability across a variety of web servers including connectors. + +Both are following the CGI specification. + +To resume, the goal is to get an Eiffel Web ecosystem based on EWSGI specification which allow to write components, libraries, applications based on EWSGI, and which can be compiled and used without changes on the various EWSGI implementations. +EWF-EWSGI is also targetting to make the connector implementations portable on the various EWSGI implementation. However this is not the most critical point, and could be address in later specification version, or maybe a specific EWSGI/Connector specification ... + +**Conclusion**: the general goal is (merely) the same for both proposals. +That is a good point, otherwise no need to compare the 2 proposals + +## Main entry point for a Web application component ## +This is the first important difference in the class EWSGI_APPLICATION + +Seibo-EWSGI: + + response (request: EWSGI_REQUEST): EWSGI_RESPONSE is + -- The response to the given 'request'. + deferred + ensure + Result.status_is_set + Result.ready_to_transmit + end + +EWF-EWSGI: + + execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER) + -- Execute the request + -- See `req.input' for input stream + -- `req.environment' for the Gateway environment + -- and `res' for the output buffer + require + res_status_unset: not res.status_is_set + deferred + ensure + res_status_set: res.status_is_set + end + +So the main difference is for the user/developer +Seibo-EWSGI: the user has to create the RESPONSE object. +EWF-EWSGI: the user has the RESPONSE_BUFFER object passed as argument, and it is ready to use. + +The consequences are important because +* Seibo-EWSGI: + - to make the creation of RESPONSE simple, the decision was to remove any notion of output stream in EWSGI. + - Then the RESPONSE has to be built before sending it. But the proposal also provides a way to get the response message by block during the transmission. A kind of delay RESPONSE filling which is for now using a read_block pattern. And this mimics the send immediately the message parts to the client. + - This design allows the developer to use its own descendant of RESPONSE and then implement the "read_block" pattern when needed. + - This also allows to control carefully that the status+headers are sent before the body. And if not using the read_block pattern, this allows to set/change the headers even after setting the message body, in fact you really build the Response as an object, and you set the various attributes whenever you want. + - The read_block pattern is meant to address the case where the message would be too big to stay in memory, and/or to send some part immediately to the client, but for that you must stick to the read_block pattern. + - Seibo team find the Response-as-Result design more natural, and adopt the Request/Response model of HTTP protocol + +* EWF-EWSGI: + - the RESPONSE_BUFFER is passed by argument to the user, then he does not have to worry about how to create it. + - it is a buffer and could be implemented in various way by the implementation(s) to access the output stream if any + - For now, there is no easy way for the user, from the proposed specification, to have a customized RESPONSE_BUFFER + - It is easy to implement the Seibo-EWSGI design on top of EWF-EWSGI (the code is provided in EWF-ewsgi implementation) + - the buffer specification allows the user to send the message parts immediately to the client without complicated pattern. As today implementation, the only restriction imposed by the design is to pass the Status code, and the headers before starting sending the message parts; this is checked by the associated assertions. However this part might be thinked again, to be more flexible, and let this to the responsibility of the user, or of other frameworks built on top of EWSGI spec. + +## Notion of output stream ## +As you might noticed +In EWF-EWSGI, the output stream is kind of hidden and replaced by the output buffer, which is in fact quite similar. However the goal is to allow the user to send immediately the message parts to the client as simple as writing in the buffer. +The EWSGI implementation will handle this buffer to integrate nicely with the underlying web server techno. This will be done through the implementation of the various connectors. + +In Seibo-EWSGI there is NO notion of output stream, this is to handle the potential case of a HTTP server technologies following CGI specification but without any output stream. +The read_block pattern allows the user to send a big response part by part, and/or also send some message parts immediately to the client during the transmission, this looks like a delayed computation of the messages. + +--- +So for now, those are the main critical (blocking) differences I (Jocelyn) can see. + +## Personal point of views ## +(Feel free to add your own point of view) + +### Jocelyn ### +* I prefer the EWF-EWSGI solution (obviously this is my proposal) mainly because with it, you can also implement the Seibo-EWSGI design. And the "more you can do, the less you can also do". +* I find the read_block pattern really not natural to use in non trivial application (even in trivial application, this might not be that easy to handle, and thus a potential source of bugs) +* I admit the need to send immediately to the client might not be the vast majority of cases. But this is useful for big messages, and for long computing message where the client wants to follow the progression (concrete cases: drupal batch, wordpress online update, ...) +* I would prefer to include the connector part into the EWSGI specification, this way any EWSGI_connector implementation could work with any EWSGI implementation. Otherwise we might end up with many different EWSGI implementations, and according to the underlying connector(s) you want to use, you will need to use different EWSGI implementations. + +### Others ... ? ### +Please contribute ... correct also the wiki page if there are mistake or misunderstanding. + From 8a3b5a77e36910e84ced2a5cac332f5c9ea9484a Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 02:57:33 -0700 Subject: [PATCH 047/178] Updated EWSGI specification: difference in main proposals (markdown) --- EWSGI-specification:-difference-in-main-proposals.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/EWSGI-specification:-difference-in-main-proposals.md b/EWSGI-specification:-difference-in-main-proposals.md index a2c2f092..608c79bf 100644 --- a/EWSGI-specification:-difference-in-main-proposals.md +++ b/EWSGI-specification:-difference-in-main-proposals.md @@ -59,7 +59,9 @@ Seibo-EWSGI: the user has to create the RESPONSE object. EWF-EWSGI: the user has the RESPONSE_BUFFER object passed as argument, and it is ready to use. The consequences are important because + * Seibo-EWSGI: + - to make the creation of RESPONSE simple, the decision was to remove any notion of output stream in EWSGI. - Then the RESPONSE has to be built before sending it. But the proposal also provides a way to get the response message by block during the transmission. A kind of delay RESPONSE filling which is for now using a read_block pattern. And this mimics the send immediately the message parts to the client. - This design allows the developer to use its own descendant of RESPONSE and then implement the "read_block" pattern when needed. @@ -68,6 +70,7 @@ The consequences are important because - Seibo team find the Response-as-Result design more natural, and adopt the Request/Response model of HTTP protocol * EWF-EWSGI: + - the RESPONSE_BUFFER is passed by argument to the user, then he does not have to worry about how to create it. - it is a buffer and could be implemented in various way by the implementation(s) to access the output stream if any - For now, there is no easy way for the user, from the proposed specification, to have a customized RESPONSE_BUFFER @@ -75,6 +78,7 @@ The consequences are important because - the buffer specification allows the user to send the message parts immediately to the client without complicated pattern. As today implementation, the only restriction imposed by the design is to pass the Status code, and the headers before starting sending the message parts; this is checked by the associated assertions. However this part might be thinked again, to be more flexible, and let this to the responsibility of the user, or of other frameworks built on top of EWSGI spec. ## Notion of output stream ## + As you might noticed In EWF-EWSGI, the output stream is kind of hidden and replaced by the output buffer, which is in fact quite similar. However the goal is to allow the user to send immediately the message parts to the client as simple as writing in the buffer. The EWSGI implementation will handle this buffer to integrate nicely with the underlying web server techno. This will be done through the implementation of the various connectors. @@ -86,9 +90,11 @@ The read_block pattern allows the user to send a big response part by part, and/ So for now, those are the main critical (blocking) differences I (Jocelyn) can see. ## Personal point of views ## + (Feel free to add your own point of view) ### Jocelyn ### + * I prefer the EWF-EWSGI solution (obviously this is my proposal) mainly because with it, you can also implement the Seibo-EWSGI design. And the "more you can do, the less you can also do". * I find the read_block pattern really not natural to use in non trivial application (even in trivial application, this might not be that easy to handle, and thus a potential source of bugs) * I admit the need to send immediately to the client might not be the vast majority of cases. But this is useful for big messages, and for long computing message where the client wants to follow the progression (concrete cases: drupal batch, wordpress online update, ...) From 45db7eb53752cdd401b39971079d83d914db9018 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 07:30:35 -0700 Subject: [PATCH 048/178] Created EWSGI: open questions (markdown) --- EWSGI:-open-questions.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 EWSGI:-open-questions.md diff --git a/EWSGI:-open-questions.md b/EWSGI:-open-questions.md new file mode 100644 index 00000000..a494a915 --- /dev/null +++ b/EWSGI:-open-questions.md @@ -0,0 +1,24 @@ +## STRING_32, UTF-8, ... ? ## +Berend raised the point that using STRING_32 is consuming 4 times the space used for STRING_8. +And CPU is cheaper than memory, so we should try to use as less memory as possible. +And then for Berend, STRING_32 is not the solution. + +Most of the data are just STRING_8 in CGI +so let's list the various request data + +- parameters (from the query string ?foo=bar&extra=blabla ) + in this case, I think the name can be url-encoded, and obviously the value too + I guess it makes sense to url-decode them + but on the other hand, we could just keep them url-encoded (as they are), and it is up to the application to url-decode them if needed. + Of course, we should provide facilities to url-decode those strings. + +- form_fields (from the POST method) + quite often, it is same kind of content that `parameters' + but .. here this might depends on the encoding for multi-parts encoding. + +- input data ... + I think this is up to the application + +note: that form fields sent by GET method, will be in `parameters' ... so maybe we should rename the "form_fields" as "post_parameters". Anyway not critical for now + +... to be continued ... From 637909614b5d4726a5069ba94b85ca26ebbe0bf1 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 07:31:08 -0700 Subject: [PATCH 049/178] Updated EWSGI: open questions (markdown) --- EWSGI:-open-questions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EWSGI:-open-questions.md b/EWSGI:-open-questions.md index a494a915..eeb2d2ac 100644 --- a/EWSGI:-open-questions.md +++ b/EWSGI:-open-questions.md @@ -6,17 +6,17 @@ And then for Berend, STRING_32 is not the solution. Most of the data are just STRING_8 in CGI so let's list the various request data -- parameters (from the query string ?foo=bar&extra=blabla ) +- **parameters** (from the query string ?foo=bar&extra=blabla ) in this case, I think the name can be url-encoded, and obviously the value too I guess it makes sense to url-decode them but on the other hand, we could just keep them url-encoded (as they are), and it is up to the application to url-decode them if needed. Of course, we should provide facilities to url-decode those strings. -- form_fields (from the POST method) +- **form_fields** (from the POST method) quite often, it is same kind of content that `parameters' but .. here this might depends on the encoding for multi-parts encoding. -- input data ... +- **input data** ... I think this is up to the application note: that form fields sent by GET method, will be in `parameters' ... so maybe we should rename the "form_fields" as "post_parameters". Anyway not critical for now From 75dc9fac3e1a8717e770c7adbe9a2ae3723981b4 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 07:32:31 -0700 Subject: [PATCH 050/178] Updated Source structure (markdown) --- Source-structure.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source-structure.md b/Source-structure.md index b49988ff..477cd4b1 100644 --- a/Source-structure.md +++ b/Source-structure.md @@ -7,8 +7,8 @@ - examples/ - tests/ - library/ -- library/ewsgi/ewsgi.ecf -- library/ewsgi/ewsgi.ecf +- library/server/ewsgi/ewsgi.ecf +- library/server/ewsgi/ewsgi.ecf Any library/component (in development mode) should follow the following structure (when not needed, there is no need to create the associated folder(s) ): @@ -18,7 +18,7 @@ Any library/component (in development mode) should follow the following structur - **.ecf** and **-safe.ecf** : configuration file - **library/** : the place to put the source code of the related library/component - **doc/** : notes, documentations, ... -- **test/** : standard place to put your tests, if you are using Eiffel Software auto-tests, I would suggest to add a new target into the associated .ecf (instead of building a new .ecf under test/ ) +- **tests/** : standard place to put your tests, if you are using Eiffel Software auto-tests, I would suggest to add a new target into the associated .ecf (instead of building a new .ecf under test/ ) - **examples/** : standard place to put the example - **build/** : a convenient place to compile your project, using this convention, you can setup utilities such as backup to ignore this folder. - **resources/** : contains pixmap files, .... From 077c140576ba9647aa2520e92dc6a4438273da20 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 07:33:41 -0700 Subject: [PATCH 051/178] Updated Home (markdown) --- Home.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Home.md b/Home.md index db832b6a..835e82bb 100644 --- a/Home.md +++ b/Home.md @@ -9,6 +9,6 @@ The official documentation/wiki is located at https://github.com/Eiffel-World/Ei - You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]] - [[list of tasks, and a potential roadmap| Tasks-Roadmap]] - [[General source structure of this project| Source-structure]] - - [[EWSGI specification| EWSGI-specification]] + - [[Eiffel Web Server Gateway Interface| EWSGI]] - [[Overview of the server side architecture| Spec-Server-Architecture]] - This project is also a collection of [[Libraries]] related to the Web \ No newline at end of file From afb3890f5073e84d6b03e2ec13db4849752ba68d Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 07:34:52 -0700 Subject: [PATCH 052/178] Updated EWSGI: open questions (markdown) --- EWSGI:-open-questions.md => EWSGI-:-open-questions.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename EWSGI:-open-questions.md => EWSGI-:-open-questions.md (100%) diff --git a/EWSGI:-open-questions.md b/EWSGI-:-open-questions.md similarity index 100% rename from EWSGI:-open-questions.md rename to EWSGI-:-open-questions.md From 59d4eb528c9ffc6de06e7de8302ecb8d3dead4cf Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 07:35:28 -0700 Subject: [PATCH 053/178] Created EWSGI (markdown) --- EWSGI.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 EWSGI.md diff --git a/EWSGI.md b/EWSGI.md new file mode 100644 index 00000000..c927f988 --- /dev/null +++ b/EWSGI.md @@ -0,0 +1,3 @@ + +- See proposed specifications: [[EWSGI specification| EWSGI-specification]] +- See [[EWSGI-:-open-questions| Open questions]] From e2fb4998536ebc834467266f32936c1b30bba4e4 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 07:35:47 -0700 Subject: [PATCH 054/178] Updated EWSGI (markdown) --- EWSGI.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/EWSGI.md b/EWSGI.md index c927f988..e986d5b6 100644 --- a/EWSGI.md +++ b/EWSGI.md @@ -1,3 +1,2 @@ - - See proposed specifications: [[EWSGI specification| EWSGI-specification]] -- See [[EWSGI-:-open-questions| Open questions]] +- See [[Open questions| EWSGI-:-open-questions]] From ed587493e914ab0718d718b8be396ca5a22e8887 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 07:39:34 -0700 Subject: [PATCH 055/178] Updated Home (markdown) --- Home.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Home.md b/Home.md index 835e82bb..050901ce 100644 --- a/Home.md +++ b/Home.md @@ -9,6 +9,6 @@ The official documentation/wiki is located at https://github.com/Eiffel-World/Ei - You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]] - [[list of tasks, and a potential roadmap| Tasks-Roadmap]] - [[General source structure of this project| Source-structure]] - - [[Eiffel Web Server Gateway Interface| EWSGI]] + - EWSGI: [[Eiffel Web Server Gateway Interface| EWSGI]] - [[Overview of the server side architecture| Spec-Server-Architecture]] - This project is also a collection of [[Libraries]] related to the Web \ No newline at end of file From c337f49c87c255503ef1b223c908a065d4ff9f2f Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 07:39:45 -0700 Subject: [PATCH 056/178] Updated EWSGI (markdown) --- EWSGI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EWSGI.md b/EWSGI.md index e986d5b6..81db53bb 100644 --- a/EWSGI.md +++ b/EWSGI.md @@ -1,2 +1,2 @@ - See proposed specifications: [[EWSGI specification| EWSGI-specification]] -- See [[Open questions| EWSGI-:-open-questions]] +- See [[Open questions| EWSGI-open-questions]] From d14e65fdc09686fd15b37f6ce23eb7c8e92fb6bf Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 2 Aug 2011 07:40:10 -0700 Subject: [PATCH 057/178] Updated EWSGI : open questions (markdown) --- EWSGI-:-open-questions.md => EWSGI-Open-Questions.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename EWSGI-:-open-questions.md => EWSGI-Open-Questions.md (100%) diff --git a/EWSGI-:-open-questions.md b/EWSGI-Open-Questions.md similarity index 100% rename from EWSGI-:-open-questions.md rename to EWSGI-Open-Questions.md From 060f1482fe4d9bcb82b3207bd27b47fcff5a3073 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 30 Aug 2011 19:16:40 +0200 Subject: [PATCH 058/178] Changed prefix class name from EWSGI_ to WGI_ changes in interface for REQUEST and RESPONSE --- EWSGI-specification.md | 169 ++++++++++++++++++++--------------------- Libraries.md | 4 +- 2 files changed, 85 insertions(+), 88 deletions(-) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index e771ef4c..07d64fa1 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -14,14 +14,14 @@ Note the following is work in progress, and reflect a specification proposal, ra For now, the specification from EWF is done in Eiffel interface please see: https://github.com/Eiffel-World/Eiffel-Web-Framework/tree/master/library/server/ewsgi/specification -EWSGI_APPLICATION +WGI_APPLICATION deferred class - EWSGI_APPLICATION + WGI_APPLICATION feature {NONE} -- Execution - execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER) + execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) -- Execute the request -- See `req.input' for input stream -- `req.environment' for the Gateway environment @@ -36,114 +36,100 @@ EWSGI_APPLICATION end -EWSGI_REQUEST +WGI_REQUEST deferred class - EWSGI_REQUEST + WGI_REQUEST feature -- Access: Input - input: EWSGI_INPUT_STREAM + input: WGI_INPUT_STREAM -- Server input channel deferred end - feature -- Access: extra values + feature -- Access: extra values request_time: detachable DATE_TIME -- Request time (UTC) deferred end - feature -- Access: environment variables + feature -- Access: CGI meta variables - environment: EWSGI_ENVIRONMENT - -- Environment variables - deferred - end - - environment_variable (a_name: STRING_8): detachable STRING_8 + meta_variable (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 -- Environment variable related to `a_name' require a_name_valid: a_name /= Void and then not a_name.is_empty deferred end - - feature -- Access: execution variables - execution_variables: EWSGI_VARIABLES [STRING_32] - -- Execution variables set by the application + meta_variables: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL] deferred end - execution_variable (a_name: STRING_8): detachable STRING_32 - -- Execution variable related to `a_name' - require - a_name_valid: a_name /= Void and then not a_name.is_empty - deferred - end - - feature -- URL Parameters + feature -- Query string Parameters - parameters: EWSGI_VARIABLES [STRING_32] + query_parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL] -- Variables extracted from QUERY_STRING deferred end - parameter (a_name: STRING_8): detachable STRING_32 + query_parameter (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 -- Parameter for name `n'. require a_name_valid: a_name /= Void and then not a_name.is_empty deferred end - + feature -- Form fields and related - form_fields: EWSGI_VARIABLES [STRING_32] + form_data_parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL] -- Variables sent by POST request deferred end - form_field (a_name: STRING_8): detachable STRING_32 + form_data_parameter (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 -- Field for name `a_name'. require a_name_valid: a_name /= Void and then not a_name.is_empty deferred end - uploaded_files: HASH_TABLE [EWSGI_UPLOADED_FILE_DATA, STRING_8] + uploaded_files: HASH_TABLE [WGI_UPLOADED_FILE_DATA, READABLE_STRING_GENERAL] -- Table of uploaded files information + --| name: original path from the user + --| type: content type + --| tmp_name: path to temp file that resides on server + --| tmp_base_name: basename of `tmp_name' + --| error: if /= 0 , there was an error : TODO ... + --| size: size of the file given by the http request deferred end - + feature -- Cookies - cookies_variables: HASH_TABLE [STRING_8, STRING_8] + cookies: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL] -- Expanded cookies variable deferred end - cookies_variable (a_name: STRING_8): detachable STRING_8 + cookie (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 -- Field for name `a_name'. require a_name_valid: a_name /= Void and then not a_name.is_empty deferred end - cookies: HASH_TABLE [EWSGI_COOKIE, STRING_8] - -- Cookies Information - deferred - end - feature -- Access: global variable - variables: HASH_TABLE [STRING_32, STRING_32] + parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL] -- Table containing all the various variables -- Warning: this is computed each time, if you change the content of other containers -- this won't update this Result's content, unless you query it again deferred end - variable (a_name: STRING_8): detachable STRING_32 + parameter (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 -- Variable named `a_name' from any of the variables container -- and following a specific order -- execution, environment, get, post, cookies @@ -151,7 +137,7 @@ EWSGI_REQUEST a_name_valid: a_name /= Void and then not a_name.is_empty deferred end - + feature -- Uploaded File Handling is_uploaded_file (a_filename: STRING_8): BOOLEAN @@ -175,12 +161,12 @@ EWSGI_REQUEST end -EWSGI_RESPONSE_BUFFER +WGI_RESPONSE_BUFFER - deferred class - EWSGI_RESPONSE_BUFFER + deferred class + WGI_RESPONSE_BUFFER - feature {EWSGI_APPLICATION} -- Commit + feature {WGI_APPLICATION} -- Commit commit -- Commit the current response @@ -190,7 +176,7 @@ EWSGI_RESPONSE_BUFFER header_committed: header_committed message_committed: message_committed end - + feature -- Status report header_committed: BOOLEAN @@ -207,15 +193,15 @@ EWSGI_RESPONSE_BUFFER -- Can message be written? deferred end - - feature {NONE} -- Core output operation - write (s: STRING_8) + feature {WGI_RESPONSE_BUFFER} -- Core output operation + + write (s: STRING) -- Send the string `s' -- this can be used for header and body deferred end - + feature -- Status setting status_is_set: BOOLEAN @@ -223,7 +209,7 @@ EWSGI_RESPONSE_BUFFER deferred end - set_status_code (a_code: INTEGER_32) + set_status_code (a_code: INTEGER) -- Set response status code -- Should be done before sending any data back to the client require @@ -235,42 +221,25 @@ EWSGI_RESPONSE_BUFFER status_set: status_is_set end - status_code: INTEGER_32 + status_code: INTEGER -- Response status deferred end - - feature -- Output operation - flush - -- Flush if it makes sense - deferred - end - - write_string (s: STRING_8) - -- Send the string `s' - require - message_writable: message_writable - deferred - end - - write_substring (s: STRING_8; a_begin_index, a_end_index: INTEGER_32) - -- Send the substring `s[a_begin_index:a_end_index]' - require - message_writable: message_writable - deferred - end - - write_file_content (fn: STRING_8) - -- Send the content of file `fn' - require - message_writable: message_writable - deferred - end - feature -- Header output operation - write_header (a_status_code: INTEGER_32; a_headers: detachable ARRAY [TUPLE [key: STRING_8; value: STRING_8]]) + write_headers_string (a_headers: STRING) + require + status_set: status_is_set + header_not_committed: not header_committed + deferred + ensure + status_set: status_is_set + header_committed: header_committed + message_writable: message_writable + end + + write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]]) -- Send headers with status `a_status', and headers from `a_headers' require status_not_set: not status_is_set @@ -279,12 +248,40 @@ EWSGI_RESPONSE_BUFFER ensure header_committed: header_committed status_set: status_is_set + message_writable: message_writable end - + + feature -- Output operation + + write_string (s: STRING) + -- Send the string `s' + require + message_writable: message_writable + deferred + end + + write_substring (s: STRING; a_begin_index, a_end_index: INTEGER) + -- Send the substring `s[a_begin_index:a_end_index]' + require + message_writable: message_writable + deferred + end + + write_file_content (fn: STRING) + -- Send the content of file `fn' + require + message_writable: message_writable + deferred + end + + flush + -- Flush if it makes sense + deferred + end + end - ## Proof-of-concept and reference implementation # Specification overview @@ -303,4 +300,4 @@ EWSGI_RESPONSE_BUFFER ## Acknowledgements -## References \ No newline at end of file +## References diff --git a/Libraries.md b/Libraries.md index 6b72e4d0..d456efcd 100644 --- a/Libraries.md +++ b/Libraries.md @@ -1,5 +1,5 @@ ## libraries currently part of the Eiffel Web Framework ## -* [[Library-EWSGI]]: Eiffel Web Server Gateway Interface (prefix GW_ for **G**ate**W**ay) +* [[Library-EWSGI]]: Eiffel Web Server Gateway Interface (prefix WGI_ for **W**eb**G**ateway**I**nterface) * [[Library-libFCGI]]: Eiffel wrapper of libfcgi SDK (http://www.fastcgi.com/devkit/libfcgi/) * [[Library-encoder]]: simple encoder for base64, url-encode, xml entities * [[Library-error]]: simple framework to handle error in EWSGI and related @@ -12,4 +12,4 @@ ## libraries that could be included, or or used ## * eMIME: MIME parser, and encoder ... -* ... \ No newline at end of file +* ... From d0576c6829c8284ec9bd4cfc4c7a41c029bba4b9 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 5 Sep 2011 06:03:33 -0700 Subject: [PATCH 059/178] Updated EWSGI Open Questions (markdown) --- EWSGI-Open-Questions.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/EWSGI-Open-Questions.md b/EWSGI-Open-Questions.md index eeb2d2ac..d6958f94 100644 --- a/EWSGI-Open-Questions.md +++ b/EWSGI-Open-Questions.md @@ -6,19 +6,20 @@ And then for Berend, STRING_32 is not the solution. Most of the data are just STRING_8 in CGI so let's list the various request data -- **parameters** (from the query string ?foo=bar&extra=blabla ) +- **query_parameter** (from the query string ?foo=bar&extra=blabla ) in this case, I think the name can be url-encoded, and obviously the value too I guess it makes sense to url-decode them but on the other hand, we could just keep them url-encoded (as they are), and it is up to the application to url-decode them if needed. Of course, we should provide facilities to url-decode those strings. -- **form_fields** (from the POST method) +- **form_data_parameter** (from the POST method) quite often, it is same kind of content that `parameters' but .. here this might depends on the encoding for multi-parts encoding. +- **meta_variable** (from the request itself ... CGI meta variables..) + I am wondering about unicode domain name ... + - **input data** ... I think this is up to the application -note: that form fields sent by GET method, will be in `parameters' ... so maybe we should rename the "form_fields" as "post_parameters". Anyway not critical for now - ... to be continued ... From 4744bb15c3610ecc0ec1c2dc53ff7cb3ca58af74 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 5 Sep 2011 06:15:07 -0700 Subject: [PATCH 060/178] Updated EWSGI (markdown) --- EWSGI.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/EWSGI.md b/EWSGI.md index 81db53bb..95dc00d7 100644 --- a/EWSGI.md +++ b/EWSGI.md @@ -1,2 +1,16 @@ - See proposed specifications: [[EWSGI specification| EWSGI-specification]] - See [[Open questions| EWSGI-open-questions]] +- And below the various calls for decisions, and effective decisions + + +### return type of parameter (and similar) should be deferred WGI_VALUE +* Description: Instead of returning READABLE_STRING_32 , it would be better to use **WGI_VALUE** . + This allows to have various types such as WGI_STRING_VALUE, WGI_LIST_VALUE, WGI_TABLE_VALUE, WGI_FILE_VALUE . + +* Status: proposed on 2011-09-05. +* **WAITING FOR APPROVAL** + +### change prefix from EWSGI_ to WGI_ +* Description: shorter and pronouncable prefix +* Status: **adopted** +* Decision: **WGI_** From 597f4bc6bdc259ae973fce0c3f1d0bd08c87630a Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 5 Sep 2011 06:54:29 -0700 Subject: [PATCH 061/178] Updated EWSGI (markdown) --- EWSGI.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/EWSGI.md b/EWSGI.md index 95dc00d7..ae0d35da 100644 --- a/EWSGI.md +++ b/EWSGI.md @@ -3,14 +3,52 @@ - And below the various calls for decisions, and effective decisions -### return type of parameter (and similar) should be deferred WGI_VALUE -* Description: Instead of returning READABLE_STRING_32 , it would be better to use **WGI_VALUE** . - This allows to have various types such as WGI_STRING_VALUE, WGI_LIST_VALUE, WGI_TABLE_VALUE, WGI_FILE_VALUE . +# In progress -* Status: proposed on 2011-09-05. -* **WAITING FOR APPROVAL** +### Return type of `parameter' (and similar query_, form_data_ ...) should be deferred WGI_VALUE +- Code: **P-2011-09-05-WGI_VALUE** +- Status: proposed on 2011-09-05. +- **WAITING FOR APPROVAL** -### change prefix from EWSGI_ to WGI_ -* Description: shorter and pronouncable prefix -* Status: **adopted** -* Decision: **WGI_** +> Instead of returning just `READABLE_STRING_32` , it would be better to use **WGI_VALUE** . +> Mainly to address the multiple value for the same param name, but also for uploaded files. +> This allows to have various types such as WGI_STRING_VALUE, WGI_LIST_VALUE, WGI_TABLE_VALUE, WGI_FILE_VALUE . +> +> Thus we would have: parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE + +### Include the parameter's name in WGI_VALUE interface +- Code: **P-2011-09-05-WGI_VALUE_interface** +- Dependence: adoption of P-2011-09-05-WGI_VALUE , may impact on P-2011-09-05-parameters_ITERABLE +- Status: proposed on 2011-09-05 **WAITING FOR APPROVAL** + +> include the corresponding parameter's name in WGI_VALUE interface. +> Such as `{WGI_VALUE}.name: READABLE_STRING_GENERAL` (or READABLE_STRING_32). +> +> This would also allow a nicer signature for `parameters: ITERABLE [WGI__VALUE]' +> instead of `parameters: ITERABLE [TUPLE [name: READABLE_STRING_GENERAL; value: WGI__VALUE]]' + +### Signature of parameters (and similar) using ITERABLE [...] +- Code: **P-2011-09-05-parameters_ITERABLE** +- Status: proposed on 2011-09-05 **WAITING FOR APPROVAL** + +> Description: Instead of forcing the implementation to use HASH_TABLE, DS_HASH_TABLE, DS_HASH_SET, ... or similar +> we should use `ITERABLE` +> +> `parameters: ITERABLE [TUPLE [name: READABLE_STRING_GENERAL; value: WGI_VALUE]]` +> +> Or, if `P-2011-09-05-WGI_VALUE_interface` is adopted (WGI_VALUE.name holds the related parameter's name) +> +> `parameters: ITERABLE [WGI_VALUE]` + +# Adopted entries + +### Change prefix from EWSGI_ to WGI_ +- Code: **P-2011-08-29-WGI_prefix** +- Status: **adopted** +- Decision: **WGI_** + +> shorter and pronouncable prefix for EWSGI class names + +# Rejected entries + +... From d0bb906a96e4b3ea4508dd06676e4c8621182865 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 5 Sep 2011 06:56:42 -0700 Subject: [PATCH 062/178] Updated EWSGI (markdown) --- EWSGI.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/EWSGI.md b/EWSGI.md index ae0d35da..c5d0ad12 100644 --- a/EWSGI.md +++ b/EWSGI.md @@ -1,11 +1,11 @@ - See proposed specifications: [[EWSGI specification| EWSGI-specification]] - See [[Open questions| EWSGI-open-questions]] -- And below the various calls for decisions, and effective decisions +- And below the various proposals and associated decision +---- +# Waiting for decision -# In progress - -### Return type of `parameter' (and similar query_, form_data_ ...) should be deferred WGI_VALUE +## Return type of `parameter' (and similar query_, form_data_ ...) should be deferred WGI_VALUE - Code: **P-2011-09-05-WGI_VALUE** - Status: proposed on 2011-09-05. - **WAITING FOR APPROVAL** @@ -16,7 +16,7 @@ > > Thus we would have: parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE -### Include the parameter's name in WGI_VALUE interface +## Include the parameter's name in WGI_VALUE interface - Code: **P-2011-09-05-WGI_VALUE_interface** - Dependence: adoption of P-2011-09-05-WGI_VALUE , may impact on P-2011-09-05-parameters_ITERABLE - Status: proposed on 2011-09-05 **WAITING FOR APPROVAL** @@ -27,7 +27,7 @@ > This would also allow a nicer signature for `parameters: ITERABLE [WGI__VALUE]' > instead of `parameters: ITERABLE [TUPLE [name: READABLE_STRING_GENERAL; value: WGI__VALUE]]' -### Signature of parameters (and similar) using ITERABLE [...] +## Signature of parameters (and similar) using ITERABLE [...] - Code: **P-2011-09-05-parameters_ITERABLE** - Status: proposed on 2011-09-05 **WAITING FOR APPROVAL** @@ -40,15 +40,17 @@ > > `parameters: ITERABLE [WGI_VALUE]` +---- # Adopted entries -### Change prefix from EWSGI_ to WGI_ +## Change prefix from EWSGI_ to WGI_ - Code: **P-2011-08-29-WGI_prefix** - Status: **adopted** - Decision: **WGI_** > shorter and pronouncable prefix for EWSGI class names +---- # Rejected entries ... From 28d03ddf2ae774cbea7b93eea77569347789dd35 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 5 Sep 2011 06:58:15 -0700 Subject: [PATCH 063/178] Updated EWSGI (markdown) --- EWSGI.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/EWSGI.md b/EWSGI.md index c5d0ad12..a8d76ae5 100644 --- a/EWSGI.md +++ b/EWSGI.md @@ -24,8 +24,9 @@ > include the corresponding parameter's name in WGI_VALUE interface. > Such as `{WGI_VALUE}.name: READABLE_STRING_GENERAL` (or READABLE_STRING_32). > -> This would also allow a nicer signature for `parameters: ITERABLE [WGI__VALUE]' -> instead of `parameters: ITERABLE [TUPLE [name: READABLE_STRING_GENERAL; value: WGI__VALUE]]' +> This would also allow to replace +> signature `parameters: ITERABLE [TUPLE [name: READABLE_STRING_GENERAL; value: WGI__VALUE]]' +> by a nicer signature `parameters: ITERABLE [WGI__VALUE]` ## Signature of parameters (and similar) using ITERABLE [...] - Code: **P-2011-09-05-parameters_ITERABLE** From 4a7b6ecc9451091de38030a820b310567de48c6f Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 5 Sep 2011 06:59:49 -0700 Subject: [PATCH 064/178] Updated EWSGI (markdown) --- EWSGI.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/EWSGI.md b/EWSGI.md index a8d76ae5..ac8c5fb6 100644 --- a/EWSGI.md +++ b/EWSGI.md @@ -7,8 +7,7 @@ ## Return type of `parameter' (and similar query_, form_data_ ...) should be deferred WGI_VALUE - Code: **P-2011-09-05-WGI_VALUE** -- Status: proposed on 2011-09-05. -- **WAITING FOR APPROVAL** +- Status: proposed on 2011-09-05 **WAITING FOR APPROVAL** > Instead of returning just `READABLE_STRING_32` , it would be better to use **WGI_VALUE** . > Mainly to address the multiple value for the same param name, but also for uploaded files. From 820bd7bd6fab591691ff5c0560452c2783c8549e Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 7 Sep 2011 05:30:29 -0700 Subject: [PATCH 065/178] Updated EWSGI (markdown) --- EWSGI.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/EWSGI.md b/EWSGI.md index ac8c5fb6..e33c0cdc 100644 --- a/EWSGI.md +++ b/EWSGI.md @@ -5,6 +5,14 @@ ---- # Waiting for decision +## Rename `parameter' into `item' +- Code: **P-2011-09-07-renaming_REQUEST_item** +- Status: proposed on 2011-09-07 **WAITING FOR APPROVAL** + +> rename `{REQUEST}.parameter (n: READABLE_STRING_GENERAL): detachable WGI_VALUE` +> into `{REQUEST}.item (n: READABLE_STRING_GENERAL): detachable WGI_VALUE` +> and similar for `parameters` -> `items` + ## Return type of `parameter' (and similar query_, form_data_ ...) should be deferred WGI_VALUE - Code: **P-2011-09-05-WGI_VALUE** - Status: proposed on 2011-09-05 **WAITING FOR APPROVAL** From 2407cb6a63a8eced8baa53aaf3327a1ceae2cd8f Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 26 Sep 2011 07:50:17 -0700 Subject: [PATCH 066/178] Updated EWSGI (markdown) --- EWSGI.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/EWSGI.md b/EWSGI.md index e33c0cdc..d27e78e4 100644 --- a/EWSGI.md +++ b/EWSGI.md @@ -5,7 +5,14 @@ ---- # Waiting for decision -## Rename `parameter' into `item' +## Include EWF_HEADER into EWSGI as WGI_HEADER +- Code: **P-2011-09-26-include-wgi-header** +- Status: proposed on 2011-09-26 **WAITING FOR APPROVAL** + +> Include WGI_HEADER to help the user to build HTTP Header. +> So that he doesn't have to know the HTTP specification for usual needs + +## Rename `parameter` into `item` - Code: **P-2011-09-07-renaming_REQUEST_item** - Status: proposed on 2011-09-07 **WAITING FOR APPROVAL** From beb721ed4bdb891a18aa7a1472375f419fb40fe7 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 26 Sep 2011 07:51:08 -0700 Subject: [PATCH 067/178] Updated EWSGI (markdown) --- EWSGI.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/EWSGI.md b/EWSGI.md index d27e78e4..18cf1419 100644 --- a/EWSGI.md +++ b/EWSGI.md @@ -5,11 +5,11 @@ ---- # Waiting for decision -## Include EWF_HEADER into EWSGI as WGI_HEADER -- Code: **P-2011-09-26-include-wgi-header** +## Include EWF_HEADER into EWSGI as WGI_HEADERS +- Code: **P-2011-09-26-include-wgi-headers** - Status: proposed on 2011-09-26 **WAITING FOR APPROVAL** -> Include WGI_HEADER to help the user to build HTTP Header. +> Include WGI_HEADERS to help the user to build HTTP Header. > So that he doesn't have to know the HTTP specification for usual needs ## Rename `parameter` into `item` From aaf8af85fd94a49f6b3417d269293aa0122c9908 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 26 Sep 2011 07:53:32 -0700 Subject: [PATCH 068/178] Updated EWSGI (markdown) --- EWSGI.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/EWSGI.md b/EWSGI.md index 18cf1419..7258848c 100644 --- a/EWSGI.md +++ b/EWSGI.md @@ -12,9 +12,13 @@ > Include WGI_HEADERS to help the user to build HTTP Header. > So that he doesn't have to know the HTTP specification for usual needs + +---- +# Adopted entries + ## Rename `parameter` into `item` - Code: **P-2011-09-07-renaming_REQUEST_item** -- Status: proposed on 2011-09-07 **WAITING FOR APPROVAL** +- Status: proposed on 2011-09-07 **ADOPTED-by-default** > rename `{REQUEST}.parameter (n: READABLE_STRING_GENERAL): detachable WGI_VALUE` > into `{REQUEST}.item (n: READABLE_STRING_GENERAL): detachable WGI_VALUE` @@ -22,7 +26,7 @@ ## Return type of `parameter' (and similar query_, form_data_ ...) should be deferred WGI_VALUE - Code: **P-2011-09-05-WGI_VALUE** -- Status: proposed on 2011-09-05 **WAITING FOR APPROVAL** +- Status: proposed on 2011-09-05 **ADOPTED-by-default** > Instead of returning just `READABLE_STRING_32` , it would be better to use **WGI_VALUE** . > Mainly to address the multiple value for the same param name, but also for uploaded files. @@ -33,7 +37,7 @@ ## Include the parameter's name in WGI_VALUE interface - Code: **P-2011-09-05-WGI_VALUE_interface** - Dependence: adoption of P-2011-09-05-WGI_VALUE , may impact on P-2011-09-05-parameters_ITERABLE -- Status: proposed on 2011-09-05 **WAITING FOR APPROVAL** +- Status: proposed on 2011-09-05 **ADOPTED-by-default** > include the corresponding parameter's name in WGI_VALUE interface. > Such as `{WGI_VALUE}.name: READABLE_STRING_GENERAL` (or READABLE_STRING_32). @@ -44,7 +48,7 @@ ## Signature of parameters (and similar) using ITERABLE [...] - Code: **P-2011-09-05-parameters_ITERABLE** -- Status: proposed on 2011-09-05 **WAITING FOR APPROVAL** +- Status: proposed on 2011-09-05 **ADOPTED-by-default** > Description: Instead of forcing the implementation to use HASH_TABLE, DS_HASH_TABLE, DS_HASH_SET, ... or similar > we should use `ITERABLE` @@ -55,9 +59,6 @@ > > `parameters: ITERABLE [WGI_VALUE]` ----- -# Adopted entries - ## Change prefix from EWSGI_ to WGI_ - Code: **P-2011-08-29-WGI_prefix** - Status: **adopted** From 2b112da43de3cbd7e659e2768460998ebd260b7f Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 26 Sep 2011 08:18:15 -0700 Subject: [PATCH 069/178] Updated EWSGI specification (markdown) --- EWSGI-specification.md | 623 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 554 insertions(+), 69 deletions(-) diff --git a/EWSGI-specification.md b/EWSGI-specification.md index 07d64fa1..750c1874 100644 --- a/EWSGI-specification.md +++ b/EWSGI-specification.md @@ -24,15 +24,14 @@ WGI_APPLICATION execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER) -- Execute the request -- See `req.input' for input stream - -- `req.environment' for the Gateway environment + -- `req.meta_variables' for the CGI meta variable -- and `res' for the output buffer require res_status_unset: not res.status_is_set deferred ensure res_status_set: res.status_is_set - res_committed: res.message_committed - end + end end @@ -40,96 +39,573 @@ WGI_REQUEST deferred class WGI_REQUEST + feature -- Access: Input - + input: WGI_INPUT_STREAM -- Server input channel deferred end feature -- Access: extra values - + request_time: detachable DATE_TIME -- Request time (UTC) deferred end feature -- Access: CGI meta variables - - meta_variable (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 + + meta_variable (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE -- Environment variable related to `a_name' require a_name_valid: a_name /= Void and then not a_name.is_empty deferred end - - meta_variables: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL] + + meta_string_variable (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 + -- Environment variable related to `a_name' + require + a_name_valid: a_name /= Void and then not a_name.is_empty + do + if attached meta_variable (a_name) as val then + Result := val.as_string + end + end + + meta_variables: ITERABLE [WGI_VALUE] + -- These variables are specific to requests made with HTTP. + -- Interpretation of these variables may depend on the value of + -- SERVER_PROTOCOL. + -- + -- Environment variables with names beginning with "HTTP_" contain + -- header data read from the client, if the protocol used was HTTP. + -- The HTTP header name is converted to upper case, has all + -- occurrences of "-" replaced with "_" and has "HTTP_" prepended to + -- give the environment variable name. The header data may be + -- presented as sent by the client, or may be rewritten in ways which + -- do not change its semantics. If multiple headers with the same + -- field-name are received then they must be rewritten as a single + -- header having the same semantics. Similarly, a header that is + -- received on more than one line must be merged onto a single line. + -- The server must, if necessary, change the representation of the + -- data (for example, the character set) to be appropriate for a CGI + -- environment variable. + -- + -- The server is not required to create environment variables for all + -- the headers that it receives. In particular, it may remove any + -- headers carrying authentication information, such as + -- "Authorization"; it may remove headers whose value is available to + -- the script via other variables, such as "Content-Length" and + -- "Content-Type". + -- + -- For convenience it might also include the following CGI entries deferred end - + + feature -- Common Gateway Interface - 1.1 8 January 1996 + + auth_type: detachable READABLE_STRING_32 + -- This variable is specific to requests made via the "http" + -- scheme. + -- + -- If the Script-URI required access authentication for external + -- access, then the server MUST set the value of this variable + -- from the 'auth-scheme' token in the request's "Authorization" + -- header field. Otherwise it is set to NULL. + -- + -- AUTH_TYPE = "" | auth-scheme + -- auth-scheme = "Basic" | "Digest" | token + -- + -- HTTP access authentication schemes are described in section 11 + -- of the HTTP/1.1 specification [8]. The auth-scheme is not + -- case-sensitive. + -- + -- Servers MUST provide this metavariable to scripts if the + -- request header included an "Authorization" field that was + -- authenticated. + deferred + end + + content_length: detachable READABLE_STRING_32 + -- This metavariable is set to the size of the message-body + -- entity attached to the request, if any, in decimal number of + -- octets. If no data are attached, then this metavariable is + -- either NULL or not defined. The syntax is the same as for the + -- HTTP "Content-Length" header field (section 14.14, HTTP/1.1 + -- specification [8]). + -- + -- CONTENT_LENGTH = "" | 1*digit + -- + -- Servers MUST provide this metavariable to scripts if the + -- request was accompanied by a message-body entity. + deferred + end + + content_length_value: NATURAL_64 + -- Integer value related to `content_length" + deferred + end + + content_type: detachable READABLE_STRING_32 + -- If the request includes a message-body, CONTENT_TYPE is set to + -- the Internet Media Type [9] of the attached entity if the type + -- was provided via a "Content-type" field in the request header, + -- or if the server can determine it in the absence of a supplied + -- "Content-type" field. The syntax is the same as for the HTTP + -- "Content-Type" header field. + -- + -- CONTENT_TYPE = "" | media-type + -- media-type = type "/" subtype *( ";" parameter) + -- type = token + -- subtype = token + -- parameter = attribute "=" value + -- attribute = token + -- value = token | quoted-string + -- + -- The type, subtype, and parameter attribute names are not + -- case-sensitive. Parameter values MAY be case sensitive. Media + -- types and their use in HTTP are described in section 3.7 of + -- the HTTP/1.1 specification [8]. + -- + -- Example: + -- + -- application/x-www-form-urlencoded + -- + -- There is no default value for this variable. If and only if it + -- is unset, then the script MAY attempt to determine the media + -- type from the data received. If the type remains unknown, then + -- the script MAY choose to either assume a content-type of + -- application/octet-stream or reject the request with a 415 + -- ("Unsupported Media Type") error. See section 7.2.1.3 for more + -- information about returning error status values. + -- + -- Servers MUST provide this metavariable to scripts if a + -- "Content-Type" field was present in the original request + -- header. If the server receives a request with an attached + -- entity but no "Content-Type" header field, it MAY attempt to + -- determine the correct datatype, or it MAY omit this + -- metavariable when communicating the request information to the + -- script. + deferred + end + + gateway_interface: READABLE_STRING_32 + -- This metavariable is set to the dialect of CGI being used by + -- the server to communicate with the script. Syntax: + -- + -- GATEWAY_INTERFACE = "CGI" "/" major "." minor + -- major = 1*digit + -- minor = 1*digit + -- + -- Note that the major and minor numbers are treated as separate + -- integers and hence each may be more than a single digit. Thus + -- CGI/2.4 is a lower version than CGI/2.13 which in turn is + -- lower than CGI/12.3. Leading zeros in either the major or the + -- minor number MUST be ignored by scripts and SHOULD NOT be + -- generated by servers. + -- + -- This document defines the 1.1 version of the CGI interface + -- ("CGI/1.1"). + -- + -- Servers MUST provide this metavariable to scripts. + -- + -- The version of the CGI specification to which this server + -- complies. Syntax: + -- + -- GATEWAY_INTERFACE = "CGI" "/" 1*digit "." 1*digit + -- + -- Note that the major and minor numbers are treated as separate + -- integers and that each may be incremented higher than a single + -- digit. Thus CGI/2.4 is a lower version than CGI/2.13 which in + -- turn is lower than CGI/12.3. Leading zeros must be ignored by + -- scripts and should never be generated by servers. + deferred + end + + path_info: READABLE_STRING_32 + -- The PATH_INFO metavariable specifies a path to be interpreted + -- by the CGI script. It identifies the resource or sub-resource + -- to be returned by the CGI script, and it is derived from the + -- portion of the URI path following the script name but + -- preceding any query data. The syntax and semantics are similar + -- to a decoded HTTP URL 'path' token (defined in RFC 2396 [4]), + -- with the exception that a PATH_INFO of "/" represents a single + -- void path segment. + -- + -- PATH_INFO = "" | ( "/" path ) + -- path = segment *( "/" segment ) + -- segment = *pchar + -- pchar = + -- + -- The PATH_INFO string is the trailing part of the + -- component of the Script-URI (see section 3.2) that follows the + -- SCRIPT_NAME portion of the path. + -- + -- Servers MAY impose their own restrictions and limitations on + -- what values they will accept for PATH_INFO, and MAY reject or + -- edit any values they consider objectionable before passing + -- them to the script. + -- + -- Servers MUST make this URI component available to CGI scripts. + -- The PATH_INFO value is case-sensitive, and the server MUST + -- preserve the case of the PATH_INFO element of the URI when + -- making it available to scripts. + deferred + end + + path_translated: detachable READABLE_STRING_32 + -- PATH_TRANSLATED is derived by taking any path-info component + -- of the request URI (see section 6.1.6), decoding it (see + -- section 3.1), parsing it as a URI in its own right, and + -- performing any virtual-to-physical translation appropriate to + -- map it onto the server's document repository structure. If the + -- request URI includes no path-info component, the + -- PATH_TRANSLATED metavariable SHOULD NOT be defined. + -- + -- + -- PATH_TRANSLATED = *CHAR + -- + -- For a request such as the following: + -- + -- http://somehost.com/cgi-bin/somescript/this%2eis%2epath%2einfo + -- + -- the PATH_INFO component would be decoded, and the result + -- parsed as though it were a request for the following: + -- + -- http://somehost.com/this.is.the.path.info + -- + -- This would then be translated to a location in the server's + -- document repository, perhaps a filesystem path something like + -- this: + -- + -- /usr/local/www/htdocs/this.is.the.path.info + -- + -- The result of the translation is the value of PATH_TRANSLATED. + -- + -- The value of PATH_TRANSLATED may or may not map to a valid + -- repository location. Servers MUST preserve the case of the + -- path-info segment if and only if the underlying repository + -- supports case-sensitive names. If the repository is only + -- case-aware, case-preserving, or case-blind with regard to + -- document names, servers are not required to preserve the case + -- of the original segment through the translation. + -- + -- The translation algorithm the server uses to derive + -- PATH_TRANSLATED is implementation defined; CGI scripts which + -- use this variable may suffer limited portability. + -- + -- Servers SHOULD provide this metavariable to scripts if and + -- only if the request URI includes a path-info component. + deferred + end + + query_string: READABLE_STRING_32 + -- A URL-encoded string; the part of the Script-URI. (See + -- section 3.2.) + -- + -- QUERY_STRING = query-string + -- query-string = *uric + -- The URL syntax for a query string is described in section 3 of + -- RFC 2396 [4]. + -- + -- Servers MUST supply this value to scripts. The QUERY_STRING + -- value is case-sensitive. If the Script-URI does not include a + -- query component, the QUERY_STRING metavariable MUST be defined + -- as an empty string (""). + deferred + end + + remote_addr: READABLE_STRING_32 + -- The IP address of the client sending the request to the + -- server. This is not necessarily that of the user agent (such + -- as if the request came through a proxy). + -- + -- REMOTE_ADDR = hostnumber + -- hostnumber = ipv4-address | ipv6-address + -- The definitions of ipv4-address and ipv6-address are provided + -- in Appendix B of RFC 2373 [13]. + -- + -- Servers MUST supply this value to scripts. + deferred + end + + remote_host: detachable READABLE_STRING_32 + -- The fully qualified domain name of the client sending the + -- request to the server, if available, otherwise NULL. (See + -- section 6.1.9.) Fully qualified domain names take the form as + -- described in section 3.5 of RFC 1034 [10] and section 2.1 of + -- RFC 1123 [5]. Domain names are not case sensitive. + -- + -- Servers SHOULD provide this information to scripts. + deferred + end + + remote_ident: detachable READABLE_STRING_32 + -- The identity information reported about the connection by a + -- RFC 1413 [11] request to the remote agent, if available. + -- Servers MAY choose not to support this feature, or not to + -- request the data for efficiency reasons. + -- + -- REMOTE_IDENT = *CHAR + -- + -- The data returned may be used for authentication purposes, but + -- the level of trust reposed in them should be minimal. + -- + -- Servers MAY supply this information to scripts if the RFC1413 + -- [11] lookup is performed. + deferred + end + + remote_user: detachable READABLE_STRING_32 + -- If the request required authentication using the "Basic" + -- mechanism (i.e., the AUTH_TYPE metavariable is set to + -- "Basic"), then the value of the REMOTE_USER metavariable is + -- set to the user-ID supplied. In all other cases the value of + -- this metavariable is undefined. + -- + -- REMOTE_USER = *OCTET + -- + -- This variable is specific to requests made via the HTTP + -- protocol. + -- + -- Servers SHOULD provide this metavariable to scripts. + deferred + end + + request_method: READABLE_STRING_32 + -- The REQUEST_METHOD metavariable is set to the method with + -- which the request was made, as described in section 5.1.1 of + -- the HTTP/1.0 specification [3] and section 5.1.1 of the + -- HTTP/1.1 specification [8]. + -- + -- REQUEST_METHOD = http-method + -- http-method = "GET" | "HEAD" | "POST" | "PUT" | "DELETE" + -- | "OPTIONS" | "TRACE" | extension-method + -- extension-method = token + -- + -- The method is case sensitive. CGI/1.1 servers MAY choose to + -- process some methods directly rather than passing them to + -- scripts. + -- + -- This variable is specific to requests made with HTTP. + -- + -- Servers MUST provide this metavariable to scripts. + deferred + end + + script_name: READABLE_STRING_32 + -- The SCRIPT_NAME metavariable is set to a URL path that could + -- identify the CGI script (rather than the script's output). The + -- syntax and semantics are identical to a decoded HTTP URL + -- 'path' token (see RFC 2396 [4]). + -- + -- SCRIPT_NAME = "" | ( "/" [ path ] ) + -- + -- The SCRIPT_NAME string is some leading part of the + -- component of the Script-URI derived in some implementation + -- defined manner. No PATH_INFO or QUERY_STRING segments (see + -- sections 6.1.6 and 6.1.8) are included in the SCRIPT_NAME + -- value. + -- + -- Servers MUST provide this metavariable to scripts. + deferred + end + + server_name: READABLE_STRING_32 + -- The SERVER_NAME metavariable is set to the name of the server, + -- as derived from the part of the Script-URI (see section + -- 3.2). + -- + -- SERVER_NAME = hostname | hostnumber + -- + -- Servers MUST provide this metavariable to scripts. + deferred + end + + server_port: INTEGER_32 + -- The SERVER_PORT metavariable is set to the port on which the + -- request was received, as used in the part of the + -- Script-URI. + -- + -- SERVER_PORT = 1*digit + -- + -- If the portion of the script-URI is blank, the actual + -- port number upon which the request was received MUST be + -- supplied. + -- + -- Servers MUST provide this metavariable to scripts. + deferred + end + + server_protocol: READABLE_STRING_32 + -- The SERVER_PROTOCOL metavariable is set to the name and + -- revision of the information protocol with which the request + -- arrived. This is not necessarily the same as the protocol + -- version used by the server in its response to the client. + -- + -- SERVER_PROTOCOL = HTTP-Version | extension-version + -- | extension-token + -- HTTP-Version = "HTTP" "/" 1*digit "." 1*digit + -- extension-version = protocol "/" 1*digit "." 1*digit + -- protocol = 1*( alpha | digit | "+" | "-" | "." ) + -- extension-token = token + -- + -- 'protocol' is a version of the part of the + -- Script-URI, but is not identical to it. For example, the + -- scheme of a request may be "https" while the protocol remains + -- "http". The protocol is not case sensitive, but by convention, + -- 'protocol' is in upper case. + -- + -- A well-known extension token value is "INCLUDED", which + -- signals that the current document is being included as part of + -- a composite document, rather than being the direct target of + -- the client request. + -- + -- Servers MUST provide this metavariable to scripts. + deferred + end + + server_software: READABLE_STRING_32 + -- The SERVER_SOFTWARE metavariable is set to the name and + -- version of the information server software answering the + -- request (and running the gateway). + -- + -- SERVER_SOFTWARE = 1*product + -- product = token [ "/" product-version ] + -- product-version = token + -- Servers MUST provide this metavariable to scripts. + deferred + end + + feature -- HTTP_* + + http_accept: detachable READABLE_STRING_32 + -- Contents of the Accept: header from the current request, if there is one. + -- Example: 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' + deferred + end + + http_accept_charset: detachable READABLE_STRING_32 + -- Contents of the Accept-Charset: header from the current request, if there is one. + -- Example: 'iso-8859-1,*,utf-8'. + deferred + end + + http_accept_encoding: detachable READABLE_STRING_32 + -- Contents of the Accept-Encoding: header from the current request, if there is one. + -- Example: 'gzip'. + deferred + end + + http_accept_language: detachable READABLE_STRING_32 + -- Contents of the Accept-Language: header from the current request, if there is one. + -- Example: 'en'. + deferred + end + + http_connection: detachable READABLE_STRING_32 + -- Contents of the Connection: header from the current request, if there is one. + -- Example: 'Keep-Alive'. + deferred + end + + http_host: detachable READABLE_STRING_32 + -- Contents of the Host: header from the current request, if there is one. + deferred + end + + http_referer: detachable READABLE_STRING_32 + -- The address of the page (if any) which referred the user agent to the current page. + -- This is set by the user agent. + -- Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. + -- In short, it cannot really be trusted. + deferred + end + + http_user_agent: detachable READABLE_STRING_32 + -- Contents of the User-Agent: header from the current request, if there is one. + -- This is a string denoting the user agent being which is accessing the page. + -- A typical example is: Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586). + -- Among other things, you can use this value to tailor your page's + -- output to the capabilities of the user agent. + deferred + end + + http_authorization: detachable READABLE_STRING_32 + -- Contents of the Authorization: header from the current request, if there is one. + deferred + end + + feature -- Extra CGI environment variables + + request_uri: READABLE_STRING_32 + -- The URI which was given in order to access this page; for instance, '/index.html'. + deferred + end + + orig_path_info: detachable READABLE_STRING_32 + -- Original version of path_info before processed by Current environment + deferred + end + feature -- Query string Parameters - - query_parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL] + + query_parameters: ITERABLE [WGI_VALUE] -- Variables extracted from QUERY_STRING deferred end - - query_parameter (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 + + query_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE -- Parameter for name `n'. require a_name_valid: a_name /= Void and then not a_name.is_empty deferred end - + feature -- Form fields and related - - form_data_parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL] + + form_data_parameters: ITERABLE [WGI_VALUE] -- Variables sent by POST request deferred end - - form_data_parameter (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 + + form_data_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE -- Field for name `a_name'. require a_name_valid: a_name /= Void and then not a_name.is_empty deferred end - + uploaded_files: HASH_TABLE [WGI_UPLOADED_FILE_DATA, READABLE_STRING_GENERAL] -- Table of uploaded files information - --| name: original path from the user - --| type: content type - --| tmp_name: path to temp file that resides on server - --| tmp_base_name: basename of `tmp_name' - --| error: if /= 0 , there was an error : TODO ... - --| size: size of the file given by the http request deferred end - + feature -- Cookies - - cookies: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL] + + cookies: ITERABLE [WGI_VALUE] -- Expanded cookies variable deferred end - - cookie (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 + + cookie (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE -- Field for name `a_name'. require a_name_valid: a_name /= Void and then not a_name.is_empty deferred end - - feature -- Access: global variable - - parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_GENERAL] + + feature -- Access: all variables + + items: ITERABLE [WGI_VALUE] -- Table containing all the various variables -- Warning: this is computed each time, if you change the content of other containers -- this won't update this Result's content, unless you query it again deferred end - - parameter (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32 + + item (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE -- Variable named `a_name' from any of the variables container -- and following a specific order -- execution, environment, get, post, cookies @@ -137,21 +613,21 @@ WGI_REQUEST a_name_valid: a_name /= Void and then not a_name.is_empty deferred end - + feature -- Uploaded File Handling - - is_uploaded_file (a_filename: STRING_8): BOOLEAN + + is_uploaded_file (a_filename: READABLE_STRING_GENERAL): BOOLEAN -- Is `a_filename' a file uploaded via HTTP POST deferred end feature -- URL Utility - + absolute_script_url (a_path: STRING_8): STRING_8 -- Absolute Url for the script if any, extended by `a_path' deferred end - + script_url (a_path: STRING_8): STRING_8 -- Url relative to script name if any, extended by `a_path' require @@ -159,15 +635,25 @@ WGI_REQUEST deferred end + invariant + server_name_not_empty: not server_name.is_empty + server_port_set: server_port /= 0 + request_method_attached: request_method /= Void + path_info_attached: path_info /= Void + query_string_attached: query_string /= Void + remote_addr_attached: remote_addr /= Void + same_orig_path_info: orig_path_info ~ meta_string_variable ({WGI_META_NAMES}.orig_path_info) + same_path_info: path_info ~ meta_string_variable ({WGI_META_NAMES}.path_info) + path_info_identical: path_info ~ meta_string_variable ({WGI_META_NAMES}.path_info) end WGI_RESPONSE_BUFFER deferred class WGI_RESPONSE_BUFFER - + feature {WGI_APPLICATION} -- Commit - + commit -- Commit the current response deferred @@ -176,39 +662,39 @@ WGI_RESPONSE_BUFFER header_committed: header_committed message_committed: message_committed end - + feature -- Status report - + header_committed: BOOLEAN -- Header committed? deferred end - + message_committed: BOOLEAN -- Message committed? deferred end - + message_writable: BOOLEAN -- Can message be written? deferred end - + feature {WGI_RESPONSE_BUFFER} -- Core output operation - - write (s: STRING) + + write (s: READABLE_STRING_8) -- Send the string `s' -- this can be used for header and body deferred end - + feature -- Status setting - + status_is_set: BOOLEAN -- Is status set? deferred end - + set_status_code (a_code: INTEGER) -- Set response status code -- Should be done before sending any data back to the client @@ -220,15 +706,15 @@ WGI_RESPONSE_BUFFER status_code_set: status_code = a_code status_set: status_is_set end - + status_code: INTEGER -- Response status deferred end - + feature -- Header output operation - - write_headers_string (a_headers: STRING) + + write_headers_string (a_headers: READABLE_STRING_8) require status_set: status_is_set header_not_committed: not header_committed @@ -238,8 +724,8 @@ WGI_RESPONSE_BUFFER header_committed: header_committed message_writable: message_writable end - - write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]]) + + write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]]) -- Send headers with status `a_status', and headers from `a_headers' require status_not_set: not status_is_set @@ -250,35 +736,34 @@ WGI_RESPONSE_BUFFER status_set: status_is_set message_writable: message_writable end - + feature -- Output operation - - write_string (s: STRING) + + write_string (s: READABLE_STRING_8) -- Send the string `s' require message_writable: message_writable deferred end - - write_substring (s: STRING; a_begin_index, a_end_index: INTEGER) + + write_substring (s: READABLE_STRING_8; a_begin_index, a_end_index: INTEGER) -- Send the substring `s[a_begin_index:a_end_index]' require message_writable: message_writable deferred end - - write_file_content (fn: STRING) + + write_file_content (fn: READABLE_STRING_8) -- Send the content of file `fn' require message_writable: message_writable deferred end - + flush -- Flush if it makes sense deferred end - end From 40ec2f6419efaf0d1d84d2a7b2c77f9fdbccfb8b Mon Sep 17 00:00:00 2001 From: jvelilla Date: Thu, 24 Nov 2011 09:22:12 -0800 Subject: [PATCH 070/178] Created HTTP client library (markdown) --- HTTP-client-library.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 HTTP-client-library.md diff --git a/HTTP-client-library.md b/HTTP-client-library.md new file mode 100644 index 00000000..f8e8380d --- /dev/null +++ b/HTTP-client-library.md @@ -0,0 +1,11 @@ +# HTTP Library Features +* HTTPS +* HTTP verbs G +* Custom data +* Custom headers +* Proxies +* Compression +* Caching +* Auth methods +* Cookies +* Redirects \ No newline at end of file From fdef9b0c8ff83b484321f785c9baa2c63f3ce73b Mon Sep 17 00:00:00 2001 From: jvelilla Date: Thu, 24 Nov 2011 09:23:42 -0800 Subject: [PATCH 071/178] Updated HTTP Library Features (markdown) --- HTTP-client-library.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/HTTP-client-library.md b/HTTP-client-library.md index f8e8380d..bcf61954 100644 --- a/HTTP-client-library.md +++ b/HTTP-client-library.md @@ -1,5 +1,8 @@ # HTTP Library Features +The following list of features are taken form the book RESTful Web Services + * HTTPS +> It must support HTTPS and SSL certificate validation. * HTTP verbs G * Custom data * Custom headers From dc0c90ab462f3d521c878c09778755b44e275847 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Thu, 24 Nov 2011 09:32:07 -0800 Subject: [PATCH 072/178] Updated HTTP Library Features (markdown) --- HTTP-client-library.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/HTTP-client-library.md b/HTTP-client-library.md index bcf61954..9d0bc436 100644 --- a/HTTP-client-library.md +++ b/HTTP-client-library.md @@ -1,14 +1,18 @@ # HTTP Library Features The following list of features are taken form the book RESTful Web Services -* HTTPS -> It must support HTTPS and SSL certificate validation. -* HTTP verbs G -* Custom data -* Custom headers -* Proxies -* Compression -* Caching -* Auth methods -* Cookies -* Redirects \ No newline at end of file +* **HTTPS**: _It must support HTTPS and SSL certificate validation_ + +* **HTTP methods**: _It must support at least the five main HTTP methods: GET, HEAD, POST, PUT, and DELETE. Optional methods + OPTIONS and TRACE, and WebDAV extensions like MOVE, ._ +* **Custom data** : _It must allow the programmer to customize the data sent as the entity-body of a +PUT or POST request._ +* **Custom headers** : _It must allow the programmer to customize a request’s HTTP headers_ +* **Response Codes** : _It must give the programmer access to the response code and headers of an HTTP +response; not just access to the entity-body._ +* **Proxies**: +* **Compression**: +* **Caching**: +* **Auth methods** : +* **Cookies** : +* **Redirects**: \ No newline at end of file From f4b621ba08498b669ec7dd37b19b501f6cad6fa2 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Thu, 24 Nov 2011 09:34:35 -0800 Subject: [PATCH 073/178] Updated HTTP Library Features (markdown) --- HTTP-client-library.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HTTP-client-library.md b/HTTP-client-library.md index 9d0bc436..02ef8653 100644 --- a/HTTP-client-library.md +++ b/HTTP-client-library.md @@ -1,5 +1,5 @@ # HTTP Library Features -The following list of features are taken form the book RESTful Web Services +The following list of features are taken form the book [RESTful Web Services](http://www.amazon.com/Restful-Web-Services-Leonard-Richardson/dp/0596529260/ref=sr_1_1?ie=UTF8&qid=1322155984&sr=8-1) * **HTTPS**: _It must support HTTPS and SSL certificate validation_ From 92c58bbbe036c01a2c3a165039c8955ca3829542 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Thu, 24 Nov 2011 09:37:45 -0800 Subject: [PATCH 074/178] Updated HTTP Library Features (markdown) --- HTTP-client-library.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/HTTP-client-library.md b/HTTP-client-library.md index 02ef8653..6e2b49b2 100644 --- a/HTTP-client-library.md +++ b/HTTP-client-library.md @@ -10,9 +10,12 @@ PUT or POST request._ * **Custom headers** : _It must allow the programmer to customize a request’s HTTP headers_ * **Response Codes** : _It must give the programmer access to the response code and headers of an HTTP response; not just access to the entity-body._ -* **Proxies**: -* **Compression**: -* **Caching**: -* **Auth methods** : +* **Proxies**: _It must be able to communicate through an HTTP proxy_ + +* **Compression**:_it should automatically request data in compressed form to save +bandwidth, and transparently decompress the data it receives._ +* **Caching**:_It should automatically cache the responses to your requests._ +* **Auth methods** : _It should transparently support the most common forms of HTTP authentication: +Basic, Digest, and WSSE._ * **Cookies** : * **Redirects**: \ No newline at end of file From 7dd9a307400b83759422308fcf4f8345048e13ca Mon Sep 17 00:00:00 2001 From: jvelilla Date: Thu, 24 Nov 2011 09:38:40 -0800 Subject: [PATCH 075/178] Updated HTTP Library Features (markdown) --- HTTP-client-library.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HTTP-client-library.md b/HTTP-client-library.md index 6e2b49b2..20a63d4f 100644 --- a/HTTP-client-library.md +++ b/HTTP-client-library.md @@ -17,5 +17,5 @@ bandwidth, and transparently decompress the data it receives._ * **Caching**:_It should automatically cache the responses to your requests._ * **Auth methods** : _It should transparently support the most common forms of HTTP authentication: Basic, Digest, and WSSE._ -* **Cookies** : -* **Redirects**: \ No newline at end of file +* **Cookies** :_It should be able to parse and create HTTP cookie strings_ +* **Redirects**:_It should be able to transparently follow HTTP redirects_ \ No newline at end of file From 8870e19991e44205e5da07b0c02c2101d4f7051d Mon Sep 17 00:00:00 2001 From: jocelyn Date: Fri, 6 Apr 2012 06:25:05 -0700 Subject: [PATCH 076/178] Updated Home (markdown) --- Home.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Home.md b/Home.md index 050901ce..c229facb 100644 --- a/Home.md +++ b/Home.md @@ -1,6 +1,6 @@ ## Eiffel-Web-Framework ## -The official documentation/wiki is located at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki , if you are visiting a "clone/fork", please always check the [[official wiki|https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki]]. +The official documentation/wiki is located at https://github.com/EiffelWebFramework/EWF/wiki , if you are visiting a "clone/fork", please always check the [[official wiki|https://github.com/EiffelWebFramework/EWF/wiki]]. - Mailing list: please visit and subscribe to the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) From 81da23c4720170e9bab5d6e85e45fda45466fd69 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 15 May 2012 10:01:41 -0700 Subject: [PATCH 077/178] Updated Home (markdown) --- Home.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Home.md b/Home.md index c229facb..9098147d 100644 --- a/Home.md +++ b/Home.md @@ -11,4 +11,6 @@ The official documentation/wiki is located at https://github.com/EiffelWebFramew - [[General source structure of this project| Source-structure]] - EWSGI: [[Eiffel Web Server Gateway Interface| EWSGI]] - [[Overview of the server side architecture| Spec-Server-Architecture]] - - This project is also a collection of [[Libraries]] related to the Web \ No newline at end of file + - This project is also a collection of [[Libraries]] related to the Web + +- This wiki needs to be updated, in the meantime, please have a look at the presentation: https://docs.google.com/presentation/d/1aI6Yps59rEW2Ci0fSeJSXpE5-2SE2Tesyj2yu1cuQKk/edit \ No newline at end of file From 167c9403c002e3c53814c4e38ba4be65fe49d75d Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 13 Jun 2012 14:08:17 -0700 Subject: [PATCH 078/178] Updated Home (markdown) --- Home.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Home.md b/Home.md index 9098147d..59860185 100644 --- a/Home.md +++ b/Home.md @@ -4,6 +4,7 @@ The official documentation/wiki is located at https://github.com/EiffelWebFramew - Mailing list: please visit and subscribe to the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) +- Most of the discussion are done on the mailing list (google group). For time to time we have web meeting, and physical meeting usually during other Eiffel related events. - See also - You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]] From 8a43e4ebb1dee678b0c84e3d7e38d11ad8af823d Mon Sep 17 00:00:00 2001 From: jocelyn Date: Thu, 14 Jun 2012 05:50:27 -0700 Subject: [PATCH 079/178] Updated Home (markdown) --- Home.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Home.md b/Home.md index 59860185..54238b40 100644 --- a/Home.md +++ b/Home.md @@ -4,7 +4,8 @@ The official documentation/wiki is located at https://github.com/EiffelWebFramew - Mailing list: please visit and subscribe to the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) -- Most of the discussion are done on the mailing list (google group). For time to time we have web meeting, and physical meeting usually during other Eiffel related events. +- Most of the topics are discussed on the mailing list (google group). +- For time to time we have web meeting, and less frequently physical meetings that occurs usually during other Eiffel related events. - See also - You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]] From 51e54311b1b7a00b6a97125930f3373997080cc6 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Thu, 14 Jun 2012 22:13:02 -0700 Subject: [PATCH 080/178] Updated Task json (markdown) --- Task-json.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Task-json.md b/Task-json.md index e8c22725..f4ccd3fe 100644 --- a/Task-json.md +++ b/Task-json.md @@ -7,4 +7,4 @@ - and then let Eiffel Software include it, in the official libraries ## Roadmap ## -- this should be done before 1st of October \ No newline at end of file +- this should be done before 1st of October - so has this been achieved? \ No newline at end of file From e2adc3cfbbcf98c9d3242aeb5847446bd8c01411 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Thu, 14 Jun 2012 22:13:52 -0700 Subject: [PATCH 081/178] Updated Tasks Roadmap (markdown) --- Tasks-Roadmap.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tasks-Roadmap.md b/Tasks-Roadmap.md index 69ba8900..e4aece3c 100644 --- a/Tasks-Roadmap.md +++ b/Tasks-Roadmap.md @@ -31,4 +31,6 @@ ## Contributors ## - See [[the collaboration page|Community-collaboration]] -note: In bold, you see the responsible for each task, but contribution from other is possible as well. \ No newline at end of file +note: In bold, you see the responsible for each task, but contribution from other is possible as well. + +This needs updating, I think. \ No newline at end of file From bd5985a99acfb94ca8837e888d4d201d1607034a Mon Sep 17 00:00:00 2001 From: colin-adams Date: Fri, 15 Jun 2012 07:10:36 -0700 Subject: [PATCH 082/178] Created Library conneg (markdown) --- Library-conneg.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 Library-conneg.md diff --git a/Library-conneg.md b/Library-conneg.md new file mode 100644 index 00000000..0a901256 --- /dev/null +++ b/Library-conneg.md @@ -0,0 +1 @@ +Testing \ No newline at end of file From d0e9438d46bc4486ca69f2973787895fca03a090 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Fri, 15 Jun 2012 07:44:14 -0700 Subject: [PATCH 083/178] Updated Library conneg (markdown) --- Library-conneg.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Library-conneg.md b/Library-conneg.md index 0a901256..7362b58a 100644 --- a/Library-conneg.md +++ b/Library-conneg.md @@ -1 +1,13 @@ -Testing \ No newline at end of file +# Server-driven content negotiation + +EWF supports server-driven content content negotiation, as defined in [HTTP/1.1 Content Negotiation](http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1) . To enable this facility: + +1. Add ${EWF}/library/network/protocol/conneg/conneg.ecf to your system ECF. +1. In the class where your handlers reside, add an attribute `conneg: CONNEG_SERVER_SIDE`, and ensure it is always attached (create in the creation procedure, or make it a once, or add an attribute body). An example creation call is: `create conneg.make ({HTTP_MIME_TYPES}.application_json, "en", "UTF-8", "")`. + +That call defines our defaults for media-type, language, charset and encoding, respectively. The encoding could also be written as `"identity"`. It means no compression. As an alternative, we might code `"gzip"`. + +The user agent (a web browser, for example. or the curl program), can request different representations by using headers. For example, `Accept: application/json; q=0.2, application/xml` says the client would be very happy to get back an XML representation (if you omit the q for quality parameter, it defaults to 1, which is best), but (s)he will tolerate JSON. Clearly, we are going to be able to satisfy that client, as we serve JSON by default. But what if the client had requested `Accept: application/xml;q=0.8, text/html`? In this example, we are going to serve both JSON and XML representations upon request. A client who requests `Accept: text/html, text/plain` is going to be disappointed. For the other aspects (language, charset and encoding), we are not going to offer any choices. That does not mean we ignore the client's headers for these aspects. We are going to check if our representation is acceptable to the client, and if not, return a 406 Not Acceptable response (an alternative is to send our representation anyway, and let the user decide whether or not to use it). + + + From 74079325a09f89f2651fdd6d45e54b017397ab99 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Fri, 15 Jun 2012 07:57:48 -0700 Subject: [PATCH 084/178] Updated Library conneg (markdown) --- Library-conneg.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Library-conneg.md b/Library-conneg.md index 7362b58a..2d43309e 100644 --- a/Library-conneg.md +++ b/Library-conneg.md @@ -9,5 +9,51 @@ That call defines our defaults for media-type, language, charset and encoding, r The user agent (a web browser, for example. or the curl program), can request different representations by using headers. For example, `Accept: application/json; q=0.2, application/xml` says the client would be very happy to get back an XML representation (if you omit the q for quality parameter, it defaults to 1, which is best), but (s)he will tolerate JSON. Clearly, we are going to be able to satisfy that client, as we serve JSON by default. But what if the client had requested `Accept: application/xml;q=0.8, text/html`? In this example, we are going to serve both JSON and XML representations upon request. A client who requests `Accept: text/html, text/plain` is going to be disappointed. For the other aspects (language, charset and encoding), we are not going to offer any choices. That does not mean we ignore the client's headers for these aspects. We are going to check if our representation is acceptable to the client, and if not, return a 406 Not Acceptable response (an alternative is to send our representation anyway, and let the user decide whether or not to use it). +Next, we need to declare all the representations we support: + +` mime_types_supported: LINKED_LIST [STRING] is + -- Media types `Current' supports + once + create Result.make + Result.put_front ({HTTP_MIME_TYPES}.application_xml) + Result.put_front ({HTTP_MIME_TYPES}.application_json) + ensure + mime_types_supported_not_void: Result /= Void + no_void_entry: not Result.has (Void) + end + + charsets_supported: LINKED_LIST [STRING] is + -- Character sets `Current' supports + once + create Result.make + Result.put_front ("UTF-8") + ensure + charsets_supported_not_void: Result /= Void + no_void_entry: not Result.has (Void) + end + + encodings_supported: LINKED_LIST [STRING] is + -- Encodings `Current' supports + once + create Result.make + Result.put_front ("identity") + Result.put_front ("") -- identity encoding + ensure + encoding_supported_not_void: Result /= Void + no_void_entry: not Result.has (Void) + end + + languages_supported: LINKED_LIST [STRING] is + -- Languages `Current' supports + once + create Result.make + Result.put_front ("en") + ensure + languages_supported_not_void: Result /= Void + no_void_entry: not Result.has (Void) + end + +Now we are in a position to do some negotiating. At the beginning of your handler(s), code: + From 53a206694a5bdd7d583be773375239f576f254f3 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Fri, 15 Jun 2012 08:04:30 -0700 Subject: [PATCH 085/178] Updated Library conneg (markdown) --- Library-conneg.md | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/Library-conneg.md b/Library-conneg.md index 2d43309e..9aa4ed8b 100644 --- a/Library-conneg.md +++ b/Library-conneg.md @@ -12,7 +12,7 @@ The user agent (a web browser, for example. or the curl program), can request di Next, we need to declare all the representations we support: ` mime_types_supported: LINKED_LIST [STRING] is - -- Media types `Current' supports + -- Media types 'Current' supports once create Result.make Result.put_front ({HTTP_MIME_TYPES}.application_xml) @@ -23,7 +23,7 @@ Next, we need to declare all the representations we support: end charsets_supported: LINKED_LIST [STRING] is - -- Character sets `Current' supports + -- Character sets 'Current' supports once create Result.make Result.put_front ("UTF-8") @@ -33,7 +33,7 @@ Next, we need to declare all the representations we support: end encodings_supported: LINKED_LIST [STRING] is - -- Encodings `Current' supports + -- Encodings 'Current' supports once create Result.make Result.put_front ("identity") @@ -44,7 +44,7 @@ Next, we need to declare all the representations we support: end languages_supported: LINKED_LIST [STRING] is - -- Languages `Current' supports + -- Languages 'Current' supports once create Result.make Result.put_front ("en") @@ -55,5 +55,20 @@ Next, we need to declare all the representations we support: Now we are in a position to do some negotiating. At the beginning of your handler(s), code: - +` +local + l_media_variants: MEDIA_TYPE_VARIANT_RESULTS + do + l_media_variants:= conneg.media_type_preference (mime_types_supported, a_req.http_accept) + if not l_media_variants.is_acceptable then + send_unacceptable_media_type (a_res) + elseif not conneg.charset_preference (charsets_supported, a_req.http_accept_charset).is_acceptable then + send_unacceptable_charset (a_res) + elseif not conneg.encoding_preference (encodings_supported, a_req.http_accept_encoding).is_acceptable then + send_unacceptable_encoding (a_res) + elseif not conneg.language_preference (languages_supported, a_req.http_accept_language).is_acceptable then + send_unacceptable_encoding (a_res) + else + -- We have agreed a representation, let's go and serve it to the client +` From c9b11a6401c61b5ab8537183070b85970d48af77 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Fri, 15 Jun 2012 08:09:39 -0700 Subject: [PATCH 086/178] Updated Library conneg (markdown) --- Library-conneg.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Library-conneg.md b/Library-conneg.md index 9aa4ed8b..4bf63725 100644 --- a/Library-conneg.md +++ b/Library-conneg.md @@ -11,8 +11,8 @@ The user agent (a web browser, for example. or the curl program), can request di Next, we need to declare all the representations we support: -` mime_types_supported: LINKED_LIST [STRING] is - -- Media types 'Current' supports + mime_types_supported: LINKED_LIST [STRING] is + -- Media types `Current' supports once create Result.make Result.put_front ({HTTP_MIME_TYPES}.application_xml) @@ -23,7 +23,7 @@ Next, we need to declare all the representations we support: end charsets_supported: LINKED_LIST [STRING] is - -- Character sets 'Current' supports + -- Character sets `Current' supports once create Result.make Result.put_front ("UTF-8") @@ -33,7 +33,7 @@ Next, we need to declare all the representations we support: end encodings_supported: LINKED_LIST [STRING] is - -- Encodings 'Current' supports + -- Encodings `Current' supports once create Result.make Result.put_front ("identity") @@ -44,7 +44,7 @@ Next, we need to declare all the representations we support: end languages_supported: LINKED_LIST [STRING] is - -- Languages 'Current' supports + -- Languages `Current' supports once create Result.make Result.put_front ("en") @@ -55,8 +55,8 @@ Next, we need to declare all the representations we support: Now we are in a position to do some negotiating. At the beginning of your handler(s), code: -` -local + + local l_media_variants: MEDIA_TYPE_VARIANT_RESULTS do l_media_variants:= conneg.media_type_preference (mime_types_supported, a_req.http_accept) From f6d64b42c66dad6392ba4e2290d0d5afd38208d6 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Fri, 15 Jun 2012 08:38:30 -0700 Subject: [PATCH 087/178] Complete. --- Library-conneg.md | 120 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 3 deletions(-) diff --git a/Library-conneg.md b/Library-conneg.md index 4bf63725..79b9d15f 100644 --- a/Library-conneg.md +++ b/Library-conneg.md @@ -58,17 +58,131 @@ Now we are in a position to do some negotiating. At the beginning of your handle local l_media_variants: MEDIA_TYPE_VARIANT_RESULTS + l_is_head: BOOLEAN + h: HTTP_HEADER + l_msg: STRING do + l_is_head := False -- or `True' if this is for a HEAD handler l_media_variants:= conneg.media_type_preference (mime_types_supported, a_req.http_accept) if not l_media_variants.is_acceptable then - send_unacceptable_media_type (a_res) + send_unacceptable_media_type (a_res, l_is_head) elseif not conneg.charset_preference (charsets_supported, a_req.http_accept_charset).is_acceptable then - send_unacceptable_charset (a_res) + send_unacceptable_charset (a_res, l_is_head) elseif not conneg.encoding_preference (encodings_supported, a_req.http_accept_encoding).is_acceptable then - send_unacceptable_encoding (a_res) + send_unacceptable_encoding (a_res, l_is_head) elseif not conneg.language_preference (languages_supported, a_req.http_accept_language).is_acceptable then send_unacceptable_encoding (a_res) else -- We have agreed a representation, let's go and serve it to the client ` +Now for those `send_unnacceptable_...` routines. They are fairly simple: + + send_unacceptable_media_type (a_res: WSF_RESPONSE; a_is_head: BOOLEAN) is + -- Send error result as text/plain that the media type is unnacceptable. + require + a_res_not_void: a_res /= Void + status_not_set: not a_res.status_is_set + header_not_committed: not a_res.header_committed + local + l_error_text: STRING + do + l_error_text := "The requested media type(s) is/are not supported by this server." + send_unacceptable (a_res, a_is_head, l_error_text) + end + + send_unacceptable_charset (a_res: WSF_RESPONSE; a_is_head: BOOLEAN) is + -- Send error result as text/plain that the character set is unnacceptable. + require + a_res_not_void: a_res /= Void + status_not_set: not a_res.status_is_set + header_not_committed: not a_res.header_committed + local + l_error_text: STRING + do + l_error_text := "The requested character set(s) is/are not supported by this server. Only UTF-8 is supported." + send_unacceptable (a_res, a_is_head, l_error_text) + end + + send_unacceptable_encoding (a_res: WSF_RESPONSE; a_is_head: BOOLEAN) is + -- Send error result as text/plain that the encoding is unnacceptable. + require + a_res_not_void: a_res /= Void + status_not_set: not a_res.status_is_set + header_not_committed: not a_res.header_committed + local + l_error_text: STRING + do + l_error_text := "The requested encoding(s) is/are not supported by this server. Only identity is supported." + send_unacceptable (a_res, a_is_head, l_error_text) + end + + send_unacceptable_language (a_res: WSF_RESPONSE; a_is_head: BOOLEAN) is + -- Send error result as text/plain that the language unnacceptable. + require + a_res_not_void: a_res /= Void + status_not_set: not a_res.status_is_set + header_not_committed: not a_res.header_committed + local + l_error_text: STRING + do + l_error_text := "The requested language(s) is/are not supported by this server. Only en (English) is supported." + send_unacceptable (a_res, a_is_head, l_error_text) + end + + send_unacceptable (a_res: WSF_RESPONSE; a_is_head: BOOLEAN; a_error_text: STRING) is + -- Send a_error_text as text/plain that a header is unnacceptable. + require + a_res_not_void: a_res /= Void + status_not_set: not a_res.status_is_set + header_not_committed: not a_res.header_committed + a_error_text_not_void: a_error_text /= Void + local + h: HTTP_HEADER + do + create h.make + set_content_type (h, Void) + h.put_content_length (a_error_text.count) + h.put_current_date + a_res.set_status_code ({HTTP_STATUS_CODE}.not_acceptable) + a_res.put_header_text (h.string) + if not a_is_head then + a_res.put_string (a_error_text) + end + end + +We'll see that `set_content_type` routine in a bit. But for now, we just have to generate the response. Let's go back to that `else ...` bit: + + else + -- We have agreed a representation, let's go and serve it to the client + create h.make + set_content_type (h, a_media_variants) + if a_media_variants.media_type ~ {HTTP_MIME_TYPES}.application_xml then + l_msg := "etc." + else + l_msg := json.value ().representation + end + h.put_content_length (l_msg.count) + h.put_current_date + a_res.set_status_code ({HTTP_STATUS_CODE}.ok) + a_res.put_header_text (h.string) + if not a_is_head then + a_res.put_string (l_msg) + end + +There's that `set_content_type` again. Finally, we will take a look at it: + + set_content_type (a_h: HTTP_HEADER; a_media_variants: MEDIA_TYPE_VARIANT_RESULTS) is + -- Set the content=type header in `a_h' according to `a_media_variants'. + require + a_h_not_void: a_h /= Void + do + if a_media_variants = Void or else not a_media_variants.is_acceptable then + a_h.put_content_type ({HTTP_MIME_TYPES}.text_plain) + else + a_h.put_content_type (a_media_variants.media_type) + end + a_h.put_header_key_value ({HTTP_HEADER_NAMES}.header_vary, {HTTP_HEADER_NAMES}.header_accept) + end + +Firstly, if we haven't agreed a media-type, then we send our (negative) response as `plain/text`. Otherwise we will send the response in the agreed media-type. But in each case we add a `Vary:Accept` header. This tells proxy caches that they have to check the media-type before returning a cached result, as there may be a different representation available. Since we do not vary our representation by language, charset or encoding, we don't add `Vary:Accept-Language,Accept-Charset,Accept-Encoding`. But if we were to negotiate different representations on those dimensions also, we would need to list the appropriate headers in the `Vary` header. \ No newline at end of file From ca6b4c468fc892b82fbae5b6337ce49564fde2ca Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 20 Jun 2012 12:53:52 -0700 Subject: [PATCH 088/178] Updated Tasks Roadmap (markdown) --- Tasks-Roadmap.md | 59 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/Tasks-Roadmap.md b/Tasks-Roadmap.md index e4aece3c..7bb685de 100644 --- a/Tasks-Roadmap.md +++ b/Tasks-Roadmap.md @@ -1,36 +1,35 @@ -## October 1st ## -* Source code , layout/handling EWR (**jfiat**) -* "Eiffel WSGI" spec (github wiki) (**paco**) -* Eiffel Web Nino (**jvelilla**) -* REST component (**jfiat**) -* Example/reference Eiffel Web Server App (**jvelilla**) - - Hello World - - Restbucks (from the book REST in Practice) -* WAMIE/apache based support for Eiffel WSGI (**daro**) - - SCOOP ... -* Some persistance solution (**daro**) -* XML, [[JSON|Task-JSON]] support (**jvelilla**) +## Future +* Focus on REST API + - Hypermedia API + - HAL, Collection/JSON ... + - ATOM, RSS, XHTML, ... ? +* Extend WSF with libraries addressing common needs + - Logging + - Caching + - Security (authentication) + OAuth (consumer+provider) + OpenID? + - Filter chain -## Maybe for October 1st ## -* Reference Client/REST-service consumer (**jfiat**) -* Mashup support, facebook, twitter, google+, ... (**jfiat**) -* Authentication support (**jfiat** ?) - - OpenID, Google Connect, Facebook Connect, OAuth, ... - - http authorization +* Start thinking about application friendly libraries + - Template engine + - State machine + - HTML5 (XHTML+JS) generation for widgets (table, suggestive box, ...) + - Google API, Twitter API, ... ? -## December ## -* Session handling - - Cookie based - - REST-based session example -* Access Control -* Application builder - - Deployment - - Persistence chooser -* Dynamic update of running system (**daro**) +* Improve documentation + - WSF documentation + tutorial + - Topic: how to contribute ? + - Example: add a "graphviz server" example, which will demonstrate an REST Hypermedia API, with logging, caching and security + +## Version 0.1 june 2012 ## +* "Eiffel WSGI" spec +* Core of Eiffel Web Framework + - EWSGI connectors: CGI, libfcgi, Nino + - WSF: request, response, router + - And utility lib, error, http, encoders, ...) +* Examples +* Documentation (tutorial inside the examples folder) +* Installation scripts ## Contributors ## - See [[the collaboration page|Community-collaboration]] -note: In bold, you see the responsible for each task, but contribution from other is possible as well. - -This needs updating, I think. \ No newline at end of file From 3d686fb50ca410586d9b8ae35d7727fbf04093af Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 20 Jun 2012 12:54:37 -0700 Subject: [PATCH 089/178] Updated Task json (markdown) --- Task-json.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Task-json.md b/Task-json.md index f4ccd3fe..8b25b368 100644 --- a/Task-json.md +++ b/Task-json.md @@ -7,4 +7,5 @@ - and then let Eiffel Software include it, in the official libraries ## Roadmap ## -- this should be done before 1st of October - so has this been achieved? \ No newline at end of file +- This task is completed. +- Future task: review the library, and improve it. \ No newline at end of file From 675f58f42b036a88a42081131ef0d74f123e15ba Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 20 Jun 2012 12:56:55 -0700 Subject: [PATCH 090/178] Updated Community collaboration (markdown) --- Community-collaboration.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Community-collaboration.md b/Community-collaboration.md index 58098906..13819d95 100644 --- a/Community-collaboration.md +++ b/Community-collaboration.md @@ -10,11 +10,16 @@ This project is a community project - Proposal from Paul Cohen for a EWSGI spec at http://eiffel.seibostudios.se/wiki/EWSGI ## Main contributors ## -- **jfiat**: Jocelyn Fiat (Eiffel Software | http://eiffel.com/) -- **jvelilla**: Hector Javier Velilla (Seibo Software Studios | http://http://seibostudios.se/en/) -- **paco**: Paul Cohen (Seibo Software Studios | http://http://seibostudios.se/en/) -- **daro**: Daniel Rodriguez (Seibo Software Studios | http://http://seibostudios.se/en/) +- **jfiat**: Jocelyn Fiat (Eiffel Software) +- **jvelilla**: Hector Javier Velilla (Seibo Software Studios) +- **paco**: Paul Cohen (Seibo Software Studios) +- **daro**: Daniel Rodriguez (Seibo Software Studios) +- Olivier Ligot (Groupe-S) +- Paul G.Crismer (Groupe-S) +- Berend de Boer (XplainHosting) +- Colin Adams (AXA R.) +- Alexander Kogtenkov (Eiffel Software) ## You want to participate ## - You are welcome to contribute (code, test, doc, code review, feedback, suggestion, spread the words ...) -- Feel free to subscribe to the mailing list +- Feel free to subscribe to the mailing list \ No newline at end of file From 9adbee9887fd1f4df3eeb571ea844283cadf321f Mon Sep 17 00:00:00 2001 From: jocelyn Date: Thu, 28 Jun 2012 22:39:41 -0700 Subject: [PATCH 091/178] Updated EWSGI specification: difference in main proposals (markdown) --- ...ls.md => EWSGI-specification---difference-in-main-proposals.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename EWSGI-specification:-difference-in-main-proposals.md => EWSGI-specification---difference-in-main-proposals.md (100%) diff --git a/EWSGI-specification:-difference-in-main-proposals.md b/EWSGI-specification---difference-in-main-proposals.md similarity index 100% rename from EWSGI-specification:-difference-in-main-proposals.md rename to EWSGI-specification---difference-in-main-proposals.md From 73319dcd8011c5a151955795c055f5714aac17a5 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Fri, 27 Jul 2012 06:55:34 -0700 Subject: [PATCH 092/178] Updated Home (markdown) --- Home.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Home.md b/Home.md index 54238b40..0795fdf1 100644 --- a/Home.md +++ b/Home.md @@ -1,18 +1,26 @@ -## Eiffel-Web-Framework ## +# Eiffel-Web-Framework # +## Location ## The official documentation/wiki is located at https://github.com/EiffelWebFramework/EWF/wiki , if you are visiting a "clone/fork", please always check the [[official wiki|https://github.com/EiffelWebFramework/EWF/wiki]]. - +## Organization ## - Mailing list: please visit and subscribe to the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) - Most of the topics are discussed on the mailing list (google group). - For time to time we have web meeting, and less frequently physical meetings that occurs usually during other Eiffel related events. -- See also - - You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]] +## Documentation ## +- to redo + +## Contributions ## +- You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]] +- Potential tasks/projects on EWF: [[Projects page| Projects]] + +## See also ## - [[list of tasks, and a potential roadmap| Tasks-Roadmap]] - [[General source structure of this project| Source-structure]] - EWSGI: [[Eiffel Web Server Gateway Interface| EWSGI]] - [[Overview of the server side architecture| Spec-Server-Architecture]] - This project is also a collection of [[Libraries]] related to the Web -- This wiki needs to be updated, in the meantime, please have a look at the presentation: https://docs.google.com/presentation/d/1aI6Yps59rEW2Ci0fSeJSXpE5-2SE2Tesyj2yu1cuQKk/edit \ No newline at end of file +## Note ## + - This wiki needs to be updated, in the meantime, please have a look at the presentation: https://docs.google.com/presentation/d/1aI6Yps59rEW2Ci0fSeJSXpE5-2SE2Tesyj2yu1cuQKk/edit \ No newline at end of file From 6a650c4a34f1813864b8d9617195c83b9aece00c Mon Sep 17 00:00:00 2001 From: jocelyn Date: Fri, 27 Jul 2012 07:41:43 -0700 Subject: [PATCH 093/178] Updated Home (markdown) --- Home.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Home.md b/Home.md index 0795fdf1..5c47ab7b 100644 --- a/Home.md +++ b/Home.md @@ -23,4 +23,4 @@ The official documentation/wiki is located at https://github.com/EiffelWebFramew - This project is also a collection of [[Libraries]] related to the Web ## Note ## - - This wiki needs to be updated, in the meantime, please have a look at the presentation: https://docs.google.com/presentation/d/1aI6Yps59rEW2Ci0fSeJSXpE5-2SE2Tesyj2yu1cuQKk/edit \ No newline at end of file + - This wiki needs to be updated, in the meantime, please have a look at the presentation: https://docs.google.com/presentation/pub?id=1GPFv6aHhTjFSLMnlAt-J4WeIHSGfHdB42dQxmOVOH8s&start=false&loop=false&delayms=3000 \ No newline at end of file From 78975fbf1cc9987658ba3fbe2706a99cabb1e803 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Fri, 27 Jul 2012 07:54:06 -0700 Subject: [PATCH 094/178] Created Projects (markdown) --- Projects.md | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 Projects.md diff --git a/Projects.md b/Projects.md new file mode 100644 index 00000000..f97c53cc --- /dev/null +++ b/Projects.md @@ -0,0 +1,107 @@ +This page lists potential projects on EWF, this is open for contribution, and if you are a student, don't hesitate to pick on, you will get close support from EWF's team. + +## Evaluate EWF according to the following constraints ... +* _Suggested by **Javier**_ +* See http://www.amundsen.com/blog/archives/1130 +* Other option is take the following REST implementation toolkit as a guide to evaluate EWF http://code.google.com/p/implementing-rest/wiki/RESTImplementationToolkit. + +## Libraries: Reusable Client Design based on J.Moore Presentation +* _Suggested by **Javier**_ +* http://s3.amazonaws.com/cimlabs/Oredev-Hypermedia-APIs.pdf +* video http://vimeo.com/20781278 + +## Hypermedia API library to work with XHTML +* _Suggested by **Javier**_ +* http://codeartisan.blogspot.com.ar/2012/07/using-html-as-media-type-for-your-api.html + +## HAL browser +* _Suggested by **Javier**_ +* written in Eiffel inspired by http://haltalk.herokuapp.com/explorer/hal_browser.html#/ +* see http://stateless.co/hal_specification.html + +## Collection-JSON browser +* _Suggested by **Javier**_ +* similar to HAL browser but focused on Collection JSON +* see http://www.amundsen.com/media-types/collection/ + +## Build a video to demonstrate how an Hypermedia API works, and how to build it using EWF +* _Suggested by **Javier**_ +* (maybe based on our graphviz example) or and extension to RestBucksCRUD + +## Create a Client Cache based on Apache commons Client Cache. +* _Suggested by **Javier**_ +* http://hc.apache.org/httpcomponents-client-ga/httpclient-cache/index.html +* http://labs.xfinity.com/benchmarking-the-httpclient-caching-module + +## Security: provide popular authentication mecanisms +* _Suggested by **Jocelyn**_ +* OAuth: consumer and provider +* OpenID +* Google Connect +* Facebook Connect +* ... + +## Build clients to consume popular RESTful APIs +* _Suggested by **Jocelyn & Javier**_ +* **Requirement**: OAuth client eiffel component +* Google Discovery APIs +* Twitter +* Facebook +* Github +* Flickr +* ... etc + +## New EWF connectors +* _Suggested by **Jocelyn & Javier**_ +* LightHTTP connector for EWF +* nginx connector for EWF +* ... + +## Design and build something like Ruby on Rails or Grails +* _Suggested by **Javier**_ +* i.e a conventional MVC to create Web Sites +* Could be useful even if this is not the taste of everyone + +## Road to Hypermedia API +* _Suggested by **Javier**_ +* describe differents types of Web API, and how you can build them using EWF. +* Describing Pros and Cons. +* based on http://martinfowler.com/articles/richardsonMaturityModel.html + +## Design a state machine to serve response +* _Suggested by **Jocelyn**_ +* example: multipage web form + +## Template engine +* _Suggested by **Jocelyn**_ +* Get inspired by any existing template engine, and build one for Eiffel + - http://www.smarty.net/ + - http://mustache.github.com/ + - ... +* This is not specific to EWF, but it will be very useful in website context + +## Wikitext, markdown parser and renderer +* _Suggested by **Jocelyn**_ +* Support reading of wikitext, and markdown, and provide HTML rendering +* extension: render wikitext and markdown into Vision2 widget (not related to EWF, but could be useful to build editor) + +## Web component to build HTML5 widget +* _Suggested by **Jocelyn**_ +* Build set of Eiffel component to ease development of websites + - table widget (with sorting ...) + - suggestive typing widget + - tab ... + - WYSIWYG textarea widget (could reuse existing JS solution ...) + - ... + +## Eiffel Web Nino +* _Suggested by **Jocelyn**_ +* Complete implementation of Eiffel Web Nino using pool of threads +* Complete migration of Eiffel Web Nino to SCOOP +* Implement persistent connection +* Improve Nino to become a real solution to host any web services/sites +* ... + +## Concurrenty and EWF +* _Suggested by **Jocelyn**_ +* Make sure EWF is compliant with concurrency, provide example From 65c9da128851e4b5fc547d61d5720f8b1c51f2f7 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Fri, 27 Jul 2012 09:23:12 -0700 Subject: [PATCH 095/178] Updated Projects (markdown) --- Projects.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Projects.md b/Projects.md index f97c53cc..727a3d6a 100644 --- a/Projects.md +++ b/Projects.md @@ -72,7 +72,7 @@ This page lists potential projects on EWF, this is open for contribution, and if * _Suggested by **Jocelyn**_ * example: multipage web form -## Template engine +## library: Template engine * _Suggested by **Jocelyn**_ * Get inspired by any existing template engine, and build one for Eiffel - http://www.smarty.net/ @@ -80,12 +80,12 @@ This page lists potential projects on EWF, this is open for contribution, and if - ... * This is not specific to EWF, but it will be very useful in website context -## Wikitext, markdown parser and renderer +## library: Wikitext, markdown parser and renderer * _Suggested by **Jocelyn**_ * Support reading of wikitext, and markdown, and provide HTML rendering * extension: render wikitext and markdown into Vision2 widget (not related to EWF, but could be useful to build editor) -## Web component to build HTML5 widget +## library: Web component to build HTML5 widget * _Suggested by **Jocelyn**_ * Build set of Eiffel component to ease development of websites - table widget (with sorting ...) @@ -105,3 +105,14 @@ This page lists potential projects on EWF, this is open for contribution, and if ## Concurrenty and EWF * _Suggested by **Jocelyn**_ * Make sure EWF is compliant with concurrency, provide example + +## Build a simple CMS with EWF +* _Suggested by **Jocelyn**_ +* Build a simple CMS website with EWF +* features: + - user management (register, login, lost password -> send email) + - page editing + - blog + - template / theme + - persistency / storage / ... + - extension at compilation time From 600e403d9134463ed89eb510c9a5d28a58e0dee7 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 30 Jul 2012 01:49:24 -0700 Subject: [PATCH 096/178] Updated Projects (markdown) --- Projects.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Projects.md b/Projects.md index 727a3d6a..bb3ec890 100644 --- a/Projects.md +++ b/Projects.md @@ -116,3 +116,8 @@ This page lists potential projects on EWF, this is open for contribution, and if - template / theme - persistency / storage / ... - extension at compilation time + +## Provide a Websocket implementation +* _Suggested by **Jocelyn**_ +* See http://en.wikipedia.org/wiki/Websocket + From 65f9b6598b0844a385babfc98098d06f1bd2f235 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 30 Jul 2012 01:54:32 -0700 Subject: [PATCH 097/178] Updated Projects (markdown) --- Projects.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Projects.md b/Projects.md index bb3ec890..29c12ddd 100644 --- a/Projects.md +++ b/Projects.md @@ -121,3 +121,6 @@ This page lists potential projects on EWF, this is open for contribution, and if * _Suggested by **Jocelyn**_ * See http://en.wikipedia.org/wiki/Websocket +## Build P2P connector +* _Suggested by **Jocelyn**_ +* Imagine you want to publish a website running on your machine (behing firewall). One would need to initiate the connection via a public website, this is common for P2P software such as remote assistance (i.e: join.me, teamviewer, showmypc, ...) \ No newline at end of file From 0647d40865b3c5651f740d96dbe80c930c1e9e84 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 30 Jul 2012 05:11:18 -0700 Subject: [PATCH 098/178] Updated Projects (markdown) --- Projects.md | 162 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 99 insertions(+), 63 deletions(-) diff --git a/Projects.md b/Projects.md index 29c12ddd..e1827609 100644 --- a/Projects.md +++ b/Projects.md @@ -1,18 +1,66 @@ This page lists potential projects on EWF, this is open for contribution, and if you are a student, don't hesitate to pick on, you will get close support from EWF's team. +# Studies/Analysis/Documentation + ## Evaluate EWF according to the following constraints ... * _Suggested by **Javier**_ * See http://www.amundsen.com/blog/archives/1130 * Other option is take the following REST implementation toolkit as a guide to evaluate EWF http://code.google.com/p/implementing-rest/wiki/RESTImplementationToolkit. -## Libraries: Reusable Client Design based on J.Moore Presentation +## Road to Hypermedia API * _Suggested by **Javier**_ -* http://s3.amazonaws.com/cimlabs/Oredev-Hypermedia-APIs.pdf -* video http://vimeo.com/20781278 +* describe differents types of Web API, and how you can build them using EWF. +* Describing Pros and Cons. +* based on http://martinfowler.com/articles/richardsonMaturityModel.html -## Hypermedia API library to work with XHTML + +## Build a video to demonstrate how an Hypermedia API works, and how to build it using EWF * _Suggested by **Javier**_ -* http://codeartisan.blogspot.com.ar/2012/07/using-html-as-media-type-for-your-api.html +* (maybe based on our graphviz example) or and extension to RestBucksCRUD + + +# Works related to EWF / framework / tools + +## Improve EWF +* _Suggested by **Jocelyn**_ +* Improve encoding support +∗ Better MIME handler +* Support for configuration +* Ready to use logging facilities +* Smart handler for HEAD or similar +* Added component to ease the caching functionalities +* Mass testing +* ... + +## Eiffel Web Nino +* _Suggested by **Javier & Jocelyn**_ +* Implement persistent connection +* Complete implementation of Eiffel Web Nino using pool of threads +* Complete migration of Eiffel Web Nino to SCOOP +* Improve Nino to become a real solution to host any web services/sites +* ... + +## New EWF connectors +* _Suggested by **Jocelyn & Javier**_ +* LightHTTP connector for EWF +* nginx connector for EWF +* ... + +## Concurrenty and EWF +* _Suggested by **Jocelyn**_ +* Make sure EWF is compliant with concurrency, provide example + +## Design and build something like Ruby on Rails or Grails +* _Suggested by **Javier**_ +* i.e a conventional MVC to create Web Sites +* Could be useful even if this is not the taste of everyone + + +## Provide a Websocket implementation +* _Suggested by **Jocelyn**_ +* See http://en.wikipedia.org/wiki/Websocket + +# Use of EWF ## HAL browser * _Suggested by **Javier**_ @@ -24,14 +72,30 @@ This page lists potential projects on EWF, this is open for contribution, and if * similar to HAL browser but focused on Collection JSON * see http://www.amundsen.com/media-types/collection/ -## Build a video to demonstrate how an Hypermedia API works, and how to build it using EWF -* _Suggested by **Javier**_ -* (maybe based on our graphviz example) or and extension to RestBucksCRUD +## Build a simple CMS with EWF +* _Suggested by **Jocelyn**_ +* Build a simple CMS website with EWF +* features: + - user management (register, login, lost password -> send email) + - page editing + - blog + - template / theme + - persistency / storage / ... + - extension at compilation time -## Create a Client Cache based on Apache commons Client Cache. +## Build P2P connector +* _Suggested by **Jocelyn**_ +* Imagine you want to publish a website running on your machine (behing firewall). One would need to initiate the connection via a public website, this is common for P2P software such as remote assistance (i.e: join.me, teamviewer, showmypc, ...) + +# Libraries + +## Hypermedia API library to work with XHTML * _Suggested by **Javier**_ -* http://hc.apache.org/httpcomponents-client-ga/httpclient-cache/index.html -* http://labs.xfinity.com/benchmarking-the-httpclient-caching-module +* http://codeartisan.blogspot.com.ar/2012/07/using-html-as-media-type-for-your-api.html + +## Add support for Mediatype such as RSS, ATOM, ... +* _Suggested by **Jocelyn**_ +* Being able to generate, and also consume RSS, ATOM, ... ## Security: provide popular authentication mecanisms * _Suggested by **Jocelyn**_ @@ -41,33 +105,6 @@ This page lists potential projects on EWF, this is open for contribution, and if * Facebook Connect * ... -## Build clients to consume popular RESTful APIs -* _Suggested by **Jocelyn & Javier**_ -* **Requirement**: OAuth client eiffel component -* Google Discovery APIs -* Twitter -* Facebook -* Github -* Flickr -* ... etc - -## New EWF connectors -* _Suggested by **Jocelyn & Javier**_ -* LightHTTP connector for EWF -* nginx connector for EWF -* ... - -## Design and build something like Ruby on Rails or Grails -* _Suggested by **Javier**_ -* i.e a conventional MVC to create Web Sites -* Could be useful even if this is not the taste of everyone - -## Road to Hypermedia API -* _Suggested by **Javier**_ -* describe differents types of Web API, and how you can build them using EWF. -* Describing Pros and Cons. -* based on http://martinfowler.com/articles/richardsonMaturityModel.html - ## Design a state machine to serve response * _Suggested by **Jocelyn**_ * example: multipage web form @@ -94,33 +131,32 @@ This page lists potential projects on EWF, this is open for contribution, and if - WYSIWYG textarea widget (could reuse existing JS solution ...) - ... -## Eiffel Web Nino -* _Suggested by **Jocelyn**_ -* Complete implementation of Eiffel Web Nino using pool of threads -* Complete migration of Eiffel Web Nino to SCOOP -* Implement persistent connection -* Improve Nino to become a real solution to host any web services/sites -* ... -## Concurrenty and EWF -* _Suggested by **Jocelyn**_ -* Make sure EWF is compliant with concurrency, provide example -## Build a simple CMS with EWF -* _Suggested by **Jocelyn**_ -* Build a simple CMS website with EWF -* features: - - user management (register, login, lost password -> send email) - - page editing - - blog - - template / theme - - persistency / storage / ... - - extension at compilation time +# Clients -## Provide a Websocket implementation -* _Suggested by **Jocelyn**_ -* See http://en.wikipedia.org/wiki/Websocket +## Libraries: Reusable Client Design based on J.Moore Presentation +* _Suggested by **Javier**_ +* Generic client that can be customized (see design in slide 12) +* http://s3.amazonaws.com/cimlabs/Oredev-Hypermedia-APIs.pdf +* video http://vimeo.com/20781278 -## Build P2P connector +## Create a Client Cache based on Apache commons Client Cache. +* _Suggested by **Javier**_ +* http://hc.apache.org/httpcomponents-client-ga/httpclient-cache/index.html +* http://labs.xfinity.com/benchmarking-the-httpclient-caching-module + +## Add SSL support to Eiffel Net * _Suggested by **Jocelyn**_ -* Imagine you want to publish a website running on your machine (behing firewall). One would need to initiate the connection via a public website, this is common for P2P software such as remote assistance (i.e: join.me, teamviewer, showmypc, ...) \ No newline at end of file +* Currently Eiffel Net does not provide any support to SSL (thus no HTTPS). For now Eiffel application often use the Eiffel cURL wrapper, but it would be more convenient to use directly Eiffel Net. + +## Build clients to consume popular RESTful APIs +* _Suggested by **Jocelyn & Javier**_ +* **Requirement**: OAuth client eiffel component +* Google Discovery APIs +* Twitter +* Facebook +* Github +* Flickr +* ... etc +* This should reuse and improve the "http_client" provided by EWF. Eventually also write the EiffelNet implementation to be independant from cURL From 8812b660da3cf820a907c2b5400073d683ba0a11 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 30 Jul 2012 05:12:24 -0700 Subject: [PATCH 099/178] Updated Projects (markdown) --- Projects.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Projects.md b/Projects.md index e1827609..ef6769d9 100644 --- a/Projects.md +++ b/Projects.md @@ -28,7 +28,9 @@ This page lists potential projects on EWF, this is open for contribution, and if * Support for configuration * Ready to use logging facilities * Smart handler for HEAD or similar -* Added component to ease the caching functionalities +* Adding component to ease the caching functionalities +* Adding Session support +* URL rewriting ? * Mass testing * ... From 8a91796d1210977221d3f0d5f47a8c8aeaf089ee Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 30 Jul 2012 05:21:14 -0700 Subject: [PATCH 100/178] Updated Projects (markdown) --- Projects.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Projects.md b/Projects.md index ef6769d9..f6a503f8 100644 --- a/Projects.md +++ b/Projects.md @@ -1,5 +1,7 @@ -This page lists potential projects on EWF, this is open for contribution, and if you are a student, don't hesitate to pick on, you will get close support from EWF's team. +This page lists potential projects on EWF, this is open for contribution. +If you are a student, don't hesitate to pick one, or even suggest a new project, or a project being a merge of several, in any case, you will get close support from EWF's team. +---- # Studies/Analysis/Documentation ## Evaluate EWF according to the following constraints ... @@ -18,7 +20,7 @@ This page lists potential projects on EWF, this is open for contribution, and if * _Suggested by **Javier**_ * (maybe based on our graphviz example) or and extension to RestBucksCRUD - +---- # Works related to EWF / framework / tools ## Improve EWF @@ -62,7 +64,8 @@ This page lists potential projects on EWF, this is open for contribution, and if * _Suggested by **Jocelyn**_ * See http://en.wikipedia.org/wiki/Websocket -# Use of EWF +---- +# Usage of EWF ## HAL browser * _Suggested by **Javier**_ @@ -84,11 +87,13 @@ This page lists potential projects on EWF, this is open for contribution, and if - template / theme - persistency / storage / ... - extension at compilation time +* The result should be used by any user to build his own CMS, and extend it easily. ## Build P2P connector * _Suggested by **Jocelyn**_ * Imagine you want to publish a website running on your machine (behing firewall). One would need to initiate the connection via a public website, this is common for P2P software such as remote assistance (i.e: join.me, teamviewer, showmypc, ...) +---- # Libraries ## Hypermedia API library to work with XHTML @@ -133,8 +138,7 @@ This page lists potential projects on EWF, this is open for contribution, and if - WYSIWYG textarea widget (could reuse existing JS solution ...) - ... - - +---- # Clients ## Libraries: Reusable Client Design based on J.Moore Presentation @@ -162,3 +166,7 @@ This page lists potential projects on EWF, this is open for contribution, and if * Flickr * ... etc * This should reuse and improve the "http_client" provided by EWF. Eventually also write the EiffelNet implementation to be independant from cURL + +---- +# Feel free to add new idea below this line +---- \ No newline at end of file From 3fc493642852e7bb07881f68a86cd265446881a4 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 31 Jul 2012 00:46:23 -0700 Subject: [PATCH 101/178] Updated Projects (markdown) --- Projects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects.md b/Projects.md index f6a503f8..26958eaa 100644 --- a/Projects.md +++ b/Projects.md @@ -2,7 +2,7 @@ This page lists potential projects on EWF, this is open for contribution. If you are a student, don't hesitate to pick one, or even suggest a new project, or a project being a merge of several, in any case, you will get close support from EWF's team. ---- -# Studies/Analysis/Documentation +# Study/Analysis/Documentation ## Evaluate EWF according to the following constraints ... * _Suggested by **Javier**_ From 38f856a54b38772785aded8acc945054ab88b7a4 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 13 Aug 2012 03:17:28 -0700 Subject: [PATCH 102/178] Updated Projects (markdown) --- Projects.md | 170 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 107 insertions(+), 63 deletions(-) diff --git a/Projects.md b/Projects.md index 26958eaa..7b7f8b61 100644 --- a/Projects.md +++ b/Projects.md @@ -6,62 +6,75 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ## Evaluate EWF according to the following constraints ... * _Suggested by **Javier**_ -* See http://www.amundsen.com/blog/archives/1130 -* Other option is take the following REST implementation toolkit as a guide to evaluate EWF http://code.google.com/p/implementing-rest/wiki/RESTImplementationToolkit. +* _Description:_ According to http://www.amundsen.com/blog/archives/1130 , evaluate the current design of EWF to see if this match the different points. An other option would be to take the following REST implementation toolkit as a guide to evaluate EWF http://code.google.com/p/implementing-rest/wiki/RESTImplementationToolkit. ## Road to Hypermedia API * _Suggested by **Javier**_ -* describe differents types of Web API, and how you can build them using EWF. -* Describing Pros and Cons. -* based on http://martinfowler.com/articles/richardsonMaturityModel.html - +* _Supervisor: _ +* _Suitability: TODO _ +* _Description: _ describe differents types of Web API, and how you can build them using EWF. Describing Pros and Cons. This should be on http://martinfowler.com/articles/richardsonMaturityModel.html ## Build a video to demonstrate how an Hypermedia API works, and how to build it using EWF * _Suggested by **Javier**_ -* (maybe based on our graphviz example) or and extension to RestBucksCRUD +* _Supervisor: _ +* _Suitability: TODO _ +* _Description:_ produce a audio+video+slide that demonstrates how to build an hypermedia API using EWF. This could be based on upcoming "graphviz server" example, or an extension of existing RestBucksCRUD example, or any new example. ---- # Works related to EWF / framework / tools ## Improve EWF * _Suggested by **Jocelyn**_ -* Improve encoding support -∗ Better MIME handler -* Support for configuration -* Ready to use logging facilities -* Smart handler for HEAD or similar -* Adding component to ease the caching functionalities -* Adding Session support -* URL rewriting ? -* Mass testing -* ... +* _Supervisor: _ +* _Suitability: TODO _ +* _Description:_ Improve existing EWF source, this is a permanent task for EWF, and this can be code, documentation, tests, ... Among others , here is a list of needed effort: +** Improve encoding support +*∗ Better MIME handler +** _Support for configuration _ +** Ready to use logging facilities +** Smart handler for HEAD or similar +** Adding component to ease the caching functionalities +** Adding Session support +** URL rewriting ? +** Mass testing +** ... ## Eiffel Web Nino * _Suggested by **Javier & Jocelyn**_ -* Implement persistent connection -* Complete implementation of Eiffel Web Nino using pool of threads -* Complete migration of Eiffel Web Nino to SCOOP -* Improve Nino to become a real solution to host any web services/sites -* ... +* _Supervisor: _ +* _Suitability: TODO _ +* _Description: _ Currently Eiffel Web Nino, is a standalone httpd server written in Eiffel. It is great for development, or embedding httpd component in application. However there are room for improvement so that one can also use it as replacement for apache, iis, ... To reach this state, here are a list of task that should be achieved: +** Implement persistent connection +** Complete implementation of Eiffel Web Nino using pool of threads +** Complete migration of Eiffel Web Nino to SCOOP +** Improve Nino to become a real solution to host any web services/sites +** ... ## New EWF connectors * _Suggested by **Jocelyn & Javier**_ -* LightHTTP connector for EWF -* nginx connector for EWF -* ... +* _Supervisor: _ +* _Suitability: TODO _ +* _Description:_ EWF is relying on the notion of "connector" to achieve portability on various platform and underlying httpd server, currently EWF support any CGI or libFCGI system (i.e apache, IIS, ...), and provide a standalone version thanks to Eiffel Web Nino. The goal now, would be to support specific connector for: +** LightHTTP (http://www.lighttpd.net/) +** nginx (http://nginx.org/en/) ## Concurrenty and EWF * _Suggested by **Jocelyn**_ -* Make sure EWF is compliant with concurrency, provide example +* _Supervisor: _ +* _Suitability: TODO _ +* _Description:_ Check that EWF is compliant with concurrency (Eiffel Thread, and SCOOP), and provide an example using concurrency. ## Design and build something like Ruby on Rails or Grails * _Suggested by **Javier**_ -* i.e a conventional MVC to create Web Sites -* Could be useful even if this is not the taste of everyone - +* _Supervisor: _ +* _Suitability: TODO _ +* _Description: _ Using EWF, design and build the set of tools to provide a conventional MVC to create Web sites. This could be useful even if this is not the taste of everyone. ## Provide a Websocket implementation * _Suggested by **Jocelyn**_ +* _Supervisor: _ +* _Suitability: TODO _ +* _Description:_ Provide an implementation of websocket with EWF and eventually Eiffel Web Nino, then demonstrate it on a simple example. WebSocket is a web technology providing for bi-directional, full-duplex communications channels over a single TCP connection. * See http://en.wikipedia.org/wiki/Websocket ---- @@ -69,73 +82,93 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ## HAL browser * _Suggested by **Javier**_ -* written in Eiffel inspired by http://haltalk.herokuapp.com/explorer/hal_browser.html#/ -* see http://stateless.co/hal_specification.html +* _Supervisor: _ +* _Suitability: TODO _ +* _Description:_ Build a HAL browser to discover an API using HAL mediatype. The browser will be able to follow the links, and display the transmitted data. This could be a vision2 application inspired by http://haltalk.herokuapp.com/explorer/hal_browser.html#/. HAL stands for Hypertext Application Language see http://stateless.co/hal_specification.html. ## Collection-JSON browser * _Suggested by **Javier**_ -* similar to HAL browser but focused on Collection JSON -* see http://www.amundsen.com/media-types/collection/ +* _Supervisor: _ +* _Suitability: TODO _ +* _Description: _ Build a Collection/JSON browser to discover an API using Collection/JSON mediatype. The browser will be able to follow the links, and display the transmitted data. This could be a vision2 application inspired by http://haltalk.herokuapp.com/explorer/hal_browser.html#/. Collection+JSON is a JSON-based read/write hypermedia-type, see http://www.amundsen.com/media-types/collection/ ## Build a simple CMS with EWF * _Suggested by **Jocelyn**_ -* Build a simple CMS website with EWF -* features: +* _Supervisor: _ +* _Suitability: TODO _ +* _Description: _ Using EWF, Build a simple CMS (Content Management System) framework and then an example. It should provide common features such as: - user management (register, login, lost password -> send email) - page editing - blog - template / theme - persistency / storage / ... - extension at compilation time -* The result should be used by any user to build his own CMS, and extend it easily. +* The result should be usable by any user to build his own CMS website, and extend it easily. ## Build P2P connector * _Suggested by **Jocelyn**_ -* Imagine you want to publish a website running on your machine (behing firewall). One would need to initiate the connection via a public website, this is common for P2P software such as remote assistance (i.e: join.me, teamviewer, showmypc, ...) +* _Supervisor: _ +* _Suitability: TODO _ +* _Description:_ Imagine you want to publish a website (or web service, API) running on your machine (behind firewall). One would need to initiate the connection via a public website, this is common for P2P software such as remote assistance (i.e: join.me, teamviewer, showmypc, ...) ---- # Libraries ## Hypermedia API library to work with XHTML * _Suggested by **Javier**_ -* http://codeartisan.blogspot.com.ar/2012/07/using-html-as-media-type-for-your-api.html +* _Supervisor: _ +* _Suitability: TODO _ +* _Description:_ Use XHTML as a media type to for hypermedia API. See http://codeartisan.blogspot.com.ar/2012/07/using-html-as-media-type-for-your-api.html ## Add support for Mediatype such as RSS, ATOM, ... * _Suggested by **Jocelyn**_ -* Being able to generate, and also consume RSS, ATOM, ... +* _Supervisor: _ +* _Suitability: TODO _ +* _Description: _ In addition to JSON, HAL, Collection+JSON, XHTML, application might want to support (read and write) standard media type such as RSS, ATOM, ... -## Security: provide popular authentication mecanisms +## Security: provide popular authentication mechanisms * _Suggested by **Jocelyn**_ -* OAuth: consumer and provider -* OpenID -* Google Connect -* Facebook Connect -* ... +* _Supervisor: _ +* _Suitability: TODO _ +* _Description:_ Any web service, web site, API need a reliable authentication mechanism, the could be on the server side or the client side to build mashup service (integrate with other web API such as google, flicker, ...). So far, EWF provides only basic HTTP Authorization, and application would need more solutions such as : + - OAuth: consumer and provider + - OpenID + - Google Connect + - Facebook Connect +* The goal is to provide component to consume other popular API/service, but also component for your own service so that other can consume it. ## Design a state machine to serve response * _Suggested by **Jocelyn**_ -* example: multipage web form +* _Supervisor: _ +* _Suitability: TODO _ +* _Description: _ In the world of Hypermedia API, the notion of state machine is pertinent, but this could also be used to provide a multi-page web form. ## library: Template engine * _Suggested by **Jocelyn**_ -* Get inspired by any existing template engine, and build one for Eiffel +* _Supervisor: _ +* _Suitability: TODO _ +* _Description:_ Get inspired by any existing template engine, and build one for Eiffel, this should be easily usable within a web application. This could be inspired, or implementation of standard template engine, this way people can reuse existing content, or migrate easily their application to EWF. For inspiration, one can look at: - http://www.smarty.net/ - http://mustache.github.com/ - - ... -* This is not specific to EWF, but it will be very useful in website context + - http://en.wikipedia.org/wiki/Template_engine_(web) ... they are plenty of them, a comparison of the different engine would help. +* This is not specific to EWF, but it will be very useful in website context. -## library: Wikitext, markdown parser and renderer +## library: Wikitext, markdown parser and render engine * _Suggested by **Jocelyn**_ -* Support reading of wikitext, and markdown, and provide HTML rendering -* extension: render wikitext and markdown into Vision2 widget (not related to EWF, but could be useful to build editor) +* _Supervisor: _ +* _Suitability: TODO _ +* _Description:_ Build component to support (read and write, and why not convert), lightweight markup language (see http://en.wikipedia.org/wiki/Lightweight_markup_language) such as wikitext, markdown, and other. The component should be able to read/scan, but also produce an HTML output. Focus first on wikitext, and markdown since they seems to be the most popular. +* Then , a nice addition would be to render those lightweight markup lang into Vision2 widget (not related to EWF, but could be useful to build (editor) desktop application) ## library: Web component to build HTML5 widget * _Suggested by **Jocelyn**_ -* Build set of Eiffel component to ease development of websites +* _Supervisor: _ +* _Suitability: TODO _ +* _Description: _ Build set of Eiffel components to ease development of websites. First this should be based on HTML5. Idea for components: - table widget (with sorting ...) - suggestive typing widget - tab ... - - WYSIWYG textarea widget (could reuse existing JS solution ...) + - WYSIWYG textarea widget (could reuse existing Javascript solution TinyMCE, CKEditor, OpenWysiwyg, ...) - ... ---- @@ -143,30 +176,41 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ## Libraries: Reusable Client Design based on J.Moore Presentation * _Suggested by **Javier**_ +* _Supervisor: _ +* _Suitability: TODO _ +* _Description: TODO _ * Generic client that can be customized (see design in slide 12) * http://s3.amazonaws.com/cimlabs/Oredev-Hypermedia-APIs.pdf * video http://vimeo.com/20781278 ## Create a Client Cache based on Apache commons Client Cache. * _Suggested by **Javier**_ +* _Supervisor: _ +* _Suitability: TODO _ +* _Description: TODO _ * http://hc.apache.org/httpcomponents-client-ga/httpclient-cache/index.html * http://labs.xfinity.com/benchmarking-the-httpclient-caching-module ## Add SSL support to Eiffel Net * _Suggested by **Jocelyn**_ -* Currently Eiffel Net does not provide any support to SSL (thus no HTTPS). For now Eiffel application often use the Eiffel cURL wrapper, but it would be more convenient to use directly Eiffel Net. +* _Supervisor: _ +* _Suitability: TODO _ +* _Description:_ Currently Eiffel Net does not provide any support to SSL (thus no HTTPS). For now Eiffel application often use the Eiffel cURL wrapper which provide SSL, but it would be more convenient to use directly Eiffel Net. Then find solution to add SSL support to EiffelNet, or to extend EiffelNet with an EiffelNet+OpenSSL solution, or other. ## Build clients to consume popular RESTful APIs * _Suggested by **Jocelyn & Javier**_ -* **Requirement**: OAuth client eiffel component -* Google Discovery APIs -* Twitter -* Facebook -* Github -* Flickr -* ... etc +* _Supervisor: _ +* _Suitability: TODO _ +* _Description: _ Build Eiffel libraries to consume popular web APIs, such as: + - Google Discovery APIs + - Twitter + - Facebook + - Github + - Flickr + - ... etc * This should reuse and improve the "http_client" provided by EWF. Eventually also write the EiffelNet implementation to be independant from cURL +* **Requirement**: OAuth client eiffel component ---- # Feel free to add new idea below this line ----- \ No newline at end of file +---- From 2f556cb99e1def1254277e2fff9c5ef66759829a Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 13 Aug 2012 03:26:44 -0700 Subject: [PATCH 103/178] Updated Projects (markdown) --- Projects.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Projects.md b/Projects.md index 7b7f8b61..5ce89750 100644 --- a/Projects.md +++ b/Projects.md @@ -214,3 +214,10 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ---- # Feel free to add new idea below this line ---- +Use the following page [[Project suggestions]] to suggest new project, or request a feature. +We'll move the content to this page for time to time. +Please provide: +* a short title +* a description +* eventual requirement +* "_Suggested by_": so that we know who suggested a feature. \ No newline at end of file From e861d65e999bacc29eae2467b968fc8cbd9f3811 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 13 Aug 2012 03:32:28 -0700 Subject: [PATCH 104/178] Created Project suggestions (markdown) --- Project-suggestions.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Project-suggestions.md diff --git a/Project-suggestions.md b/Project-suggestions.md new file mode 100644 index 00000000..aac79df3 --- /dev/null +++ b/Project-suggestions.md @@ -0,0 +1,12 @@ +Use this to suggest new projects, or request features. +The content of this page will be moved to the main [[Projects]] page for time to time. +For any entry, please use this template + +---- +## Short title +* _Suggested by **your name**_": so that we know who suggested a feature. +* **Requirement**: ... if any, otherwise remove this line +* _Description: ..._ a few lines to describe the project +* _References: ..._ if any, otherwise remove this line +---- + From 764b076b886e016b73360ad6ca3e795da1d651a3 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 13 Aug 2012 03:32:52 -0700 Subject: [PATCH 105/178] Updated Project suggestions (markdown) --- Project-suggestions.md => Projects---Suggestions.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Project-suggestions.md => Projects---Suggestions.md (100%) diff --git a/Project-suggestions.md b/Projects---Suggestions.md similarity index 100% rename from Project-suggestions.md rename to Projects---Suggestions.md From dc3a897150d5fea6098dad1637207da4fd1004e9 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 13 Aug 2012 03:33:18 -0700 Subject: [PATCH 106/178] Updated Projects Suggestions (markdown) --- Projects---Suggestions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects---Suggestions.md b/Projects---Suggestions.md index aac79df3..b0878697 100644 --- a/Projects---Suggestions.md +++ b/Projects---Suggestions.md @@ -6,7 +6,7 @@ For any entry, please use this template ## Short title * _Suggested by **your name**_": so that we know who suggested a feature. * **Requirement**: ... if any, otherwise remove this line -* _Description: ..._ a few lines to describe the project +* _Description: ... _ a few lines to describe the project * _References: ..._ if any, otherwise remove this line ---- From a7577bb3303a1aba908e6e2c1b2aae05eadf110f Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 13 Aug 2012 03:33:58 -0700 Subject: [PATCH 107/178] Updated Projects Suggestions (markdown) --- Projects---Suggestions.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Projects---Suggestions.md b/Projects---Suggestions.md index b0878697..f3050b76 100644 --- a/Projects---Suggestions.md +++ b/Projects---Suggestions.md @@ -3,10 +3,12 @@ The content of this page will be moved to the main [[Projects]] page for time t For any entry, please use this template ---- + ## Short title * _Suggested by **your name**_": so that we know who suggested a feature. * **Requirement**: ... if any, otherwise remove this line * _Description: ... _ a few lines to describe the project -* _References: ..._ if any, otherwise remove this line +* _References: ... _ if any, otherwise remove this line + ---- From 26706841a5b6f72c58f78c44f32df29f67c5cecb Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 13 Aug 2012 03:34:55 -0700 Subject: [PATCH 108/178] Updated Projects Suggestions (markdown) --- Projects---Suggestions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Projects---Suggestions.md b/Projects---Suggestions.md index f3050b76..b7278fee 100644 --- a/Projects---Suggestions.md +++ b/Projects---Suggestions.md @@ -7,8 +7,8 @@ For any entry, please use this template ## Short title * _Suggested by **your name**_": so that we know who suggested a feature. * **Requirement**: ... if any, otherwise remove this line -* _Description: ... _ a few lines to describe the project -* _References: ... _ if any, otherwise remove this line +* _Description_: ... a few lines to describe the project +* _References_: ... if any, otherwise remove this line ---- From c92be6de09825f92b7a52faa8a14a7a8351e96f6 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 13 Aug 2012 03:35:26 -0700 Subject: [PATCH 109/178] Updated Projects (markdown) --- Projects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects.md b/Projects.md index 5ce89750..49c60a29 100644 --- a/Projects.md +++ b/Projects.md @@ -214,7 +214,7 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ---- # Feel free to add new idea below this line ---- -Use the following page [[Project suggestions]] to suggest new project, or request a feature. +Use the following page [[Projects Suggestions]] to suggest new project, or request a feature. We'll move the content to this page for time to time. Please provide: * a short title From 97018e93f6f926b6d80a6dbf40bbf2730a8d03ff Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 13 Aug 2012 03:39:54 -0700 Subject: [PATCH 110/178] Updated Projects (markdown) --- Projects.md | 146 +++++++++++++++++++++++++--------------------------- 1 file changed, 70 insertions(+), 76 deletions(-) diff --git a/Projects.md b/Projects.md index 49c60a29..5cf4823e 100644 --- a/Projects.md +++ b/Projects.md @@ -6,28 +6,28 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ## Evaluate EWF according to the following constraints ... * _Suggested by **Javier**_ -* _Description:_ According to http://www.amundsen.com/blog/archives/1130 , evaluate the current design of EWF to see if this match the different points. An other option would be to take the following REST implementation toolkit as a guide to evaluate EWF http://code.google.com/p/implementing-rest/wiki/RESTImplementationToolkit. +* _Description_: According to http://www.amundsen.com/blog/archives/1130 , evaluate the current design of EWF to see if this match the different points. An other option would be to take the following REST implementation toolkit as a guide to evaluate EWF http://code.google.com/p/implementing-rest/wiki/RESTImplementationToolkit. ## Road to Hypermedia API * _Suggested by **Javier**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description: _ describe differents types of Web API, and how you can build them using EWF. Describing Pros and Cons. This should be on http://martinfowler.com/articles/richardsonMaturityModel.html +* _Supervisor_: +* _Suitability_: +* _Description_: describe differents types of Web API, and how you can build them using EWF. Describing Pros and Cons. This should be on http://martinfowler.com/articles/richardsonMaturityModel.html ## Build a video to demonstrate how an Hypermedia API works, and how to build it using EWF * _Suggested by **Javier**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description:_ produce a audio+video+slide that demonstrates how to build an hypermedia API using EWF. This could be based on upcoming "graphviz server" example, or an extension of existing RestBucksCRUD example, or any new example. +* _Supervisor_: +* _Suitability_: TODO +* _Description_: produce a audio+video+slide that demonstrates how to build an hypermedia API using EWF. This could be based on upcoming "graphviz server" example, or an extension of existing RestBucksCRUD example, or any new example. ---- # Works related to EWF / framework / tools ## Improve EWF * _Suggested by **Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description:_ Improve existing EWF source, this is a permanent task for EWF, and this can be code, documentation, tests, ... Among others , here is a list of needed effort: +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Improve existing EWF source, this is a permanent task for EWF, and this can be code, documentation, tests, ... Among others , here is a list of needed effort: ** Improve encoding support *∗ Better MIME handler ** _Support for configuration _ @@ -41,9 +41,9 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ## Eiffel Web Nino * _Suggested by **Javier & Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description: _ Currently Eiffel Web Nino, is a standalone httpd server written in Eiffel. It is great for development, or embedding httpd component in application. However there are room for improvement so that one can also use it as replacement for apache, iis, ... To reach this state, here are a list of task that should be achieved: +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Currently Eiffel Web Nino, is a standalone httpd server written in Eiffel. It is great for development, or embedding httpd component in application. However there are room for improvement so that one can also use it as replacement for apache, iis, ... To reach this state, here are a list of task that should be achieved: ** Implement persistent connection ** Complete implementation of Eiffel Web Nino using pool of threads ** Complete migration of Eiffel Web Nino to SCOOP @@ -52,29 +52,29 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ## New EWF connectors * _Suggested by **Jocelyn & Javier**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description:_ EWF is relying on the notion of "connector" to achieve portability on various platform and underlying httpd server, currently EWF support any CGI or libFCGI system (i.e apache, IIS, ...), and provide a standalone version thanks to Eiffel Web Nino. The goal now, would be to support specific connector for: +* _Supervisor_: +* _Suitability_: TODO +* _Description_: EWF is relying on the notion of "connector" to achieve portability on various platform and underlying httpd server, currently EWF support any CGI or libFCGI system (i.e apache, IIS, ...), and provide a standalone version thanks to Eiffel Web Nino. The goal now, would be to support specific connector for: ** LightHTTP (http://www.lighttpd.net/) ** nginx (http://nginx.org/en/) ## Concurrenty and EWF * _Suggested by **Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description:_ Check that EWF is compliant with concurrency (Eiffel Thread, and SCOOP), and provide an example using concurrency. +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Check that EWF is compliant with concurrency (Eiffel Thread, and SCOOP), and provide an example using concurrency. ## Design and build something like Ruby on Rails or Grails * _Suggested by **Javier**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description: _ Using EWF, design and build the set of tools to provide a conventional MVC to create Web sites. This could be useful even if this is not the taste of everyone. +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Using EWF, design and build the set of tools to provide a conventional MVC to create Web sites. This could be useful even if this is not the taste of everyone. ## Provide a Websocket implementation * _Suggested by **Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description:_ Provide an implementation of websocket with EWF and eventually Eiffel Web Nino, then demonstrate it on a simple example. WebSocket is a web technology providing for bi-directional, full-duplex communications channels over a single TCP connection. +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Provide an implementation of websocket with EWF and eventually Eiffel Web Nino, then demonstrate it on a simple example. WebSocket is a web technology providing for bi-directional, full-duplex communications channels over a single TCP connection. * See http://en.wikipedia.org/wiki/Websocket ---- @@ -82,21 +82,21 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ## HAL browser * _Suggested by **Javier**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description:_ Build a HAL browser to discover an API using HAL mediatype. The browser will be able to follow the links, and display the transmitted data. This could be a vision2 application inspired by http://haltalk.herokuapp.com/explorer/hal_browser.html#/. HAL stands for Hypertext Application Language see http://stateless.co/hal_specification.html. +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Build a HAL browser to discover an API using HAL mediatype. The browser will be able to follow the links, and display the transmitted data. This could be a vision2 application inspired by http://haltalk.herokuapp.com/explorer/hal_browser.html#/. HAL stands for Hypertext Application Language see http://stateless.co/hal_specification.html. ## Collection-JSON browser * _Suggested by **Javier**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description: _ Build a Collection/JSON browser to discover an API using Collection/JSON mediatype. The browser will be able to follow the links, and display the transmitted data. This could be a vision2 application inspired by http://haltalk.herokuapp.com/explorer/hal_browser.html#/. Collection+JSON is a JSON-based read/write hypermedia-type, see http://www.amundsen.com/media-types/collection/ +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Build a Collection/JSON browser to discover an API using Collection/JSON mediatype. The browser will be able to follow the links, and display the transmitted data. This could be a vision2 application inspired by http://haltalk.herokuapp.com/explorer/hal_browser.html#/. Collection+JSON is a JSON-based read/write hypermedia-type, see http://www.amundsen.com/media-types/collection/ ## Build a simple CMS with EWF * _Suggested by **Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description: _ Using EWF, Build a simple CMS (Content Management System) framework and then an example. It should provide common features such as: +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Using EWF, Build a simple CMS (Content Management System) framework and then an example. It should provide common features such as: - user management (register, login, lost password -> send email) - page editing - blog @@ -107,30 +107,30 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ## Build P2P connector * _Suggested by **Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description:_ Imagine you want to publish a website (or web service, API) running on your machine (behind firewall). One would need to initiate the connection via a public website, this is common for P2P software such as remote assistance (i.e: join.me, teamviewer, showmypc, ...) +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Imagine you want to publish a website (or web service, API) running on your machine (behind firewall). One would need to initiate the connection via a public website, this is common for P2P software such as remote assistance (i.e: join.me, teamviewer, showmypc, ...) ---- # Libraries ## Hypermedia API library to work with XHTML * _Suggested by **Javier**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description:_ Use XHTML as a media type to for hypermedia API. See http://codeartisan.blogspot.com.ar/2012/07/using-html-as-media-type-for-your-api.html +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Use XHTML as a media type to for hypermedia API. See http://codeartisan.blogspot.com.ar/2012/07/using-html-as-media-type-for-your-api.html ## Add support for Mediatype such as RSS, ATOM, ... * _Suggested by **Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description: _ In addition to JSON, HAL, Collection+JSON, XHTML, application might want to support (read and write) standard media type such as RSS, ATOM, ... +* _Supervisor_: +* _Suitability_: TODO +* _Description_: In addition to JSON, HAL, Collection+JSON, XHTML, application might want to support (read and write) standard media type such as RSS, ATOM, ... ## Security: provide popular authentication mechanisms * _Suggested by **Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description:_ Any web service, web site, API need a reliable authentication mechanism, the could be on the server side or the client side to build mashup service (integrate with other web API such as google, flicker, ...). So far, EWF provides only basic HTTP Authorization, and application would need more solutions such as : +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Any web service, web site, API need a reliable authentication mechanism, the could be on the server side or the client side to build mashup service (integrate with other web API such as google, flicker, ...). So far, EWF provides only basic HTTP Authorization, and application would need more solutions such as : - OAuth: consumer and provider - OpenID - Google Connect @@ -139,15 +139,15 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ## Design a state machine to serve response * _Suggested by **Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description: _ In the world of Hypermedia API, the notion of state machine is pertinent, but this could also be used to provide a multi-page web form. +* _Supervisor_: +* _Suitability_: TODO +* _Description_: In the world of Hypermedia API, the notion of state machine is pertinent, but this could also be used to provide a multi-page web form. ## library: Template engine * _Suggested by **Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description:_ Get inspired by any existing template engine, and build one for Eiffel, this should be easily usable within a web application. This could be inspired, or implementation of standard template engine, this way people can reuse existing content, or migrate easily their application to EWF. For inspiration, one can look at: +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Get inspired by any existing template engine, and build one for Eiffel, this should be easily usable within a web application. This could be inspired, or implementation of standard template engine, this way people can reuse existing content, or migrate easily their application to EWF. For inspiration, one can look at: - http://www.smarty.net/ - http://mustache.github.com/ - http://en.wikipedia.org/wiki/Template_engine_(web) ... they are plenty of them, a comparison of the different engine would help. @@ -155,16 +155,16 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ## library: Wikitext, markdown parser and render engine * _Suggested by **Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description:_ Build component to support (read and write, and why not convert), lightweight markup language (see http://en.wikipedia.org/wiki/Lightweight_markup_language) such as wikitext, markdown, and other. The component should be able to read/scan, but also produce an HTML output. Focus first on wikitext, and markdown since they seems to be the most popular. +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Build component to support (read and write, and why not convert), lightweight markup language (see http://en.wikipedia.org/wiki/Lightweight_markup_language) such as wikitext, markdown, and other. The component should be able to read/scan, but also produce an HTML output. Focus first on wikitext, and markdown since they seems to be the most popular. * Then , a nice addition would be to render those lightweight markup lang into Vision2 widget (not related to EWF, but could be useful to build (editor) desktop application) ## library: Web component to build HTML5 widget * _Suggested by **Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description: _ Build set of Eiffel components to ease development of websites. First this should be based on HTML5. Idea for components: +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Build set of Eiffel components to ease development of websites. First this should be based on HTML5. Idea for components: - table widget (with sorting ...) - suggestive typing widget - tab ... @@ -176,32 +176,32 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ## Libraries: Reusable Client Design based on J.Moore Presentation * _Suggested by **Javier**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description: TODO _ +* _Supervisor_: +* _Suitability_: TODO +* _Description_: TODO * Generic client that can be customized (see design in slide 12) * http://s3.amazonaws.com/cimlabs/Oredev-Hypermedia-APIs.pdf * video http://vimeo.com/20781278 ## Create a Client Cache based on Apache commons Client Cache. * _Suggested by **Javier**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description: TODO _ +* _Supervisor_: +* _Suitability_: TODO +* _Description_: TODO * http://hc.apache.org/httpcomponents-client-ga/httpclient-cache/index.html * http://labs.xfinity.com/benchmarking-the-httpclient-caching-module ## Add SSL support to Eiffel Net * _Suggested by **Jocelyn**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description:_ Currently Eiffel Net does not provide any support to SSL (thus no HTTPS). For now Eiffel application often use the Eiffel cURL wrapper which provide SSL, but it would be more convenient to use directly Eiffel Net. Then find solution to add SSL support to EiffelNet, or to extend EiffelNet with an EiffelNet+OpenSSL solution, or other. +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Currently Eiffel Net does not provide any support to SSL (thus no HTTPS). For now Eiffel application often use the Eiffel cURL wrapper which provide SSL, but it would be more convenient to use directly Eiffel Net. Then find solution to add SSL support to EiffelNet, or to extend EiffelNet with an EiffelNet+OpenSSL solution, or other. ## Build clients to consume popular RESTful APIs * _Suggested by **Jocelyn & Javier**_ -* _Supervisor: _ -* _Suitability: TODO _ -* _Description: _ Build Eiffel libraries to consume popular web APIs, such as: +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Build Eiffel libraries to consume popular web APIs, such as: - Google Discovery APIs - Twitter - Facebook @@ -215,9 +215,3 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, # Feel free to add new idea below this line ---- Use the following page [[Projects Suggestions]] to suggest new project, or request a feature. -We'll move the content to this page for time to time. -Please provide: -* a short title -* a description -* eventual requirement -* "_Suggested by_": so that we know who suggested a feature. \ No newline at end of file From 693b5b2d1b4fa91e7991ec1a56f67be826cdb89b Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 13 Aug 2012 03:40:22 -0700 Subject: [PATCH 111/178] Updated Projects Suggestions (markdown) --- Projects---Suggestions.md => Projects--Suggestions.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Projects---Suggestions.md => Projects--Suggestions.md (100%) diff --git a/Projects---Suggestions.md b/Projects--Suggestions.md similarity index 100% rename from Projects---Suggestions.md rename to Projects--Suggestions.md From 681e331dec24f22671f199f600912025adcc5733 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 13 Aug 2012 03:40:44 -0700 Subject: [PATCH 112/178] Updated Projects Suggestions (markdown) --- Projects--Suggestions.md => Projects-new-suggestions.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Projects--Suggestions.md => Projects-new-suggestions.md (100%) diff --git a/Projects--Suggestions.md b/Projects-new-suggestions.md similarity index 100% rename from Projects--Suggestions.md rename to Projects-new-suggestions.md From 55fc25b25869a066131108c9ca49d0114389809e Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 13 Aug 2012 03:41:07 -0700 Subject: [PATCH 113/178] Updated Projects (markdown) --- Projects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects.md b/Projects.md index 5cf4823e..dda1a146 100644 --- a/Projects.md +++ b/Projects.md @@ -214,4 +214,4 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, ---- # Feel free to add new idea below this line ---- -Use the following page [[Projects Suggestions]] to suggest new project, or request a feature. +Use the following page [[Projects new suggestions]] to suggest new project, or request a feature. \ No newline at end of file From a29bbab0a8dbd46b3c400181806455f9f4dce10a Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 14 Aug 2012 01:16:50 -0700 Subject: [PATCH 114/178] Updated Projects (markdown) --- Projects.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Projects.md b/Projects.md index dda1a146..ad4f235f 100644 --- a/Projects.md +++ b/Projects.md @@ -137,11 +137,25 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, - Facebook Connect * The goal is to provide component to consume other popular API/service, but also component for your own service so that other can consume it. -## Design a state machine to serve response +## Security: provide popular authentication mechanisms * _Suggested by **Jocelyn**_ * _Supervisor_: * _Suitability_: TODO -* _Description_: In the world of Hypermedia API, the notion of state machine is pertinent, but this could also be used to provide a multi-page web form. +* _Description_: Any web service, web site, API need a reliable authentication mechanism, the could be on the server side or the client side to build mashup service (integrate with other web API such as google, flicker, ...). So far, EWF provides only basic HTTP Authorization, and application would need more solutions such as : + - OAuth: consumer and provider + - OpenID + - Google Connect + - Facebook Connect +* The goal is to provide component to consume other popular API/service, but also component for your own service so that other can consume it. + +## Provide a SSO (Single Sign On) implementation (server, and clients) +* _Suggested by **Jocelyn**_ +* _Supervisor_: +* _Suitability_: TODO +* _Description_: Design and build a Single Sign On implementation for Eiffel. That should include the authentication server, and at least one Eiffel client component (it would be convenient to also provide php, js, ...). In the same spirit, having Eiffel client for popular SSO server would be appreciated as well. +* _Reference_: + - http://en.wikipedia.org/wiki/Single_sign-on + - http://en.wikipedia.org/wiki/List_of_single_sign-on_implementations ## library: Template engine * _Suggested by **Jocelyn**_ From 15d12b86aa7063bcb2a97a57d3739eab3489211e Mon Sep 17 00:00:00 2001 From: oligot Date: Fri, 24 Aug 2012 02:54:47 -0700 Subject: [PATCH 115/178] Add support for Swagger --- Projects-new-suggestions.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Projects-new-suggestions.md b/Projects-new-suggestions.md index b7278fee..23e0a613 100644 --- a/Projects-new-suggestions.md +++ b/Projects-new-suggestions.md @@ -12,3 +12,9 @@ For any entry, please use this template ---- +## Add support for Swagger +* _Suggested by **Olivier**_ +* _Description_: Build a Swagger Eiffel implementation +* _References_: http://swagger.wordnik.com/ + +---- \ No newline at end of file From 6e767477721d714027234bc4fbadda6e1d235dae Mon Sep 17 00:00:00 2001 From: oligot Date: Fri, 14 Sep 2012 01:16:00 -0700 Subject: [PATCH 116/178] Created Web meeting 2012 09 18 (markdown) --- Web-meeting-2012-09-18.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Web-meeting-2012-09-18.md diff --git a/Web-meeting-2012-09-18.md b/Web-meeting-2012-09-18.md new file mode 100644 index 00000000..19a0279b --- /dev/null +++ b/Web-meeting-2012-09-18.md @@ -0,0 +1,32 @@ +## Participants + +* Jocelyn Fiat +* Berend de Boer +* Olivier Ligot +* Javier Velilla +* Alexander Kogtenkov + +## Information + +### When ? +Tuesday 18th of september, ? time (see http://www.doodle.com/8v2sekiyebp4dpyh) + +### Where ? +Web meeting using webex + +Short url: ? + +Long url: ? + +## Agenda + +* Current status of EWF + * Current activities + * Remaining issues +* Future tasks +* Users feedback, suggestions and requests +* Next meeting + +## Materials + +## Minutes \ No newline at end of file From f820d25a9e7d5667ace29701a0cad74a89973f33 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Mon, 17 Sep 2012 10:04:24 -0700 Subject: [PATCH 117/178] Updated Web meeting 2012 09 18 (markdown) --- Web-meeting-2012-09-18.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Web-meeting-2012-09-18.md b/Web-meeting-2012-09-18.md index 19a0279b..be000bac 100644 --- a/Web-meeting-2012-09-18.md +++ b/Web-meeting-2012-09-18.md @@ -9,13 +9,12 @@ ## Information ### When ? -Tuesday 18th of september, ? time (see http://www.doodle.com/8v2sekiyebp4dpyh) +Tuesday 18th of september, 19:00 - 20:00 UTC/GMT time (see http://www.doodle.com/8v2sekiyebp4dpyh) ### Where ? Web meeting using webex -Short url: ? - +Short url: visit this page before the meeting Long url: ? ## Agenda @@ -23,6 +22,8 @@ Long url: ? * Current status of EWF * Current activities * Remaining issues + * Focus on new design for the router system + * Demo for a CMS built with EWF (inspired by Drupal) * Future tasks * Users feedback, suggestions and requests * Next meeting From 2b82e7f07ffc1e6d2016961d15691e5d73abdf67 Mon Sep 17 00:00:00 2001 From: oligot Date: Mon, 17 Sep 2012 11:42:18 -0700 Subject: [PATCH 118/178] Updated Web meeting 2012 09 18 (markdown) --- Web-meeting-2012-09-18.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Web-meeting-2012-09-18.md b/Web-meeting-2012-09-18.md index be000bac..eb4e39a7 100644 --- a/Web-meeting-2012-09-18.md +++ b/Web-meeting-2012-09-18.md @@ -25,6 +25,7 @@ Long url: ? * Focus on new design for the router system * Demo for a CMS built with EWF (inspired by Drupal) * Future tasks + * [graphviz-server](https://github.com/EiffelWebFramework/graphviz-server) * Users feedback, suggestions and requests * Next meeting From 2b00192e877ebf2adf4b22c0e012f1a6b8f9aa03 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 18 Sep 2012 06:04:13 -0700 Subject: [PATCH 119/178] Updated Web meeting 2012 09 18 (markdown) --- Web-meeting-2012-09-18.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Web-meeting-2012-09-18.md b/Web-meeting-2012-09-18.md index eb4e39a7..bdcfd5c4 100644 --- a/Web-meeting-2012-09-18.md +++ b/Web-meeting-2012-09-18.md @@ -9,13 +9,14 @@ ## Information ### When ? -Tuesday 18th of september, 19:00 - 20:00 UTC/GMT time (see http://www.doodle.com/8v2sekiyebp4dpyh) +Tuesday 18th of september, 19:00 - 20:00 UTC/GMT time (see 3rd time in http://www.doodle.com/8v2sekiyebp4dpyh) ### Where ? Web meeting using webex -Short url: visit this page before the meeting -Long url: ? +Short url: http://goo.gl/wBz11 + +Long url: https://eiffel.webex.com/eiffel/j.php?ED=211265702&UID=0&PW=NZWNiMjBiZWIz&RT=MiMyMA%3D%3D ## Agenda From b1fcedf501be0a104f29647c4e3e3ed69d5ae000 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 18 Sep 2012 06:06:12 -0700 Subject: [PATCH 120/178] Updated Web meeting 2012 09 18 (markdown) --- Web-meeting-2012-09-18.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Web-meeting-2012-09-18.md b/Web-meeting-2012-09-18.md index bdcfd5c4..9a56b6c1 100644 --- a/Web-meeting-2012-09-18.md +++ b/Web-meeting-2012-09-18.md @@ -14,9 +14,9 @@ Tuesday 18th of september, 19:00 - 20:00 UTC/GMT time (see 3rd time in http://ww ### Where ? Web meeting using webex -Short url: http://goo.gl/wBz11 - -Long url: https://eiffel.webex.com/eiffel/j.php?ED=211265702&UID=0&PW=NZWNiMjBiZWIz&RT=MiMyMA%3D%3D +* Short url: http://goo.gl/wBz11 +* Long url: https://eiffel.webex.com/eiffel/j.php?ED=211265702&UID=0&PW=NZWNiMjBiZWIz&RT=MiMyMA%3D%3D +* Related Google group topic: https://groups.google.com/d/topic/eiffel-web-framework/A7ADPAT3nj8/discussion ## Agenda From ad12d3e16d4be8b8743366c23e42d41d20eba58e Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 18 Sep 2012 06:24:31 -0700 Subject: [PATCH 121/178] Updated Web meeting 2012 09 18 (markdown) --- Web-meeting-2012-09-18.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Web-meeting-2012-09-18.md b/Web-meeting-2012-09-18.md index 9a56b6c1..0b0cce23 100644 --- a/Web-meeting-2012-09-18.md +++ b/Web-meeting-2012-09-18.md @@ -9,7 +9,7 @@ ## Information ### When ? -Tuesday 18th of september, 19:00 - 20:00 UTC/GMT time (see 3rd time in http://www.doodle.com/8v2sekiyebp4dpyh) +* Tuesday 18th of september, 19:00 - 20:00 UTC/GMT time (see 3rd time in http://www.doodle.com/8v2sekiyebp4dpyh) ### Where ? Web meeting using webex @@ -21,13 +21,25 @@ Web meeting using webex ## Agenda * Current status of EWF + * Focus on new design for the router system, and take decision + * decide if this replace the previous system, + * or if this is provided as another solution (we would then have 2 routers system). + * It might be possible to implement the previous uri and uri-template router with the new design, and mark them obsolete, this would avoid breaking existing code, but if no-one ask for it, no need to spend time doing it. * Current activities + * Technology forecasting about REST, Hypermedia API, Collection/JSON, HAL, ... + * Building a CMS framework inspired by Drupal, and using EWF + * Libraries in-progress or draft: OAuth (consumer), Google API, Github API, Template engine, Wikitext parser, CMS (including sub libraries which will be part of EWF, such as session handling, mailer, ...) + * Documentation * Remaining issues - * Focus on new design for the router system + * Review design in relation to concurrency, and provide example demonstrating concurrency with EWF + * Review design to allow easier extension/customization of EWF, such as using its own MIME handlers. * Demo for a CMS built with EWF (inspired by Drupal) * Future tasks * [graphviz-server](https://github.com/EiffelWebFramework/graphviz-server) + * Improving Eiffel Web Nino: to support persistent connection, and better concurrency design. + * Provide friendly components to generate HTML (DHTML, HTML5, ...), (coders do not want to learn HTML and CSS) * Users feedback, suggestions and requests + * ... * Next meeting ## Materials From eea428831c4acc2cc17aa9e91a334961fecfd04e Mon Sep 17 00:00:00 2001 From: oligot Date: Tue, 18 Sep 2012 06:57:38 -0700 Subject: [PATCH 122/178] Updated Web meeting 2012 09 18 (markdown) --- Web-meeting-2012-09-18.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Web-meeting-2012-09-18.md b/Web-meeting-2012-09-18.md index 0b0cce23..d4ebe99f 100644 --- a/Web-meeting-2012-09-18.md +++ b/Web-meeting-2012-09-18.md @@ -4,7 +4,7 @@ * Berend de Boer * Olivier Ligot * Javier Velilla -* Alexander Kogtenkov +* Emmanuel Stapf ## Information From 9229b6609120bcf2d4e89b5e37472bc227263f06 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 18 Sep 2012 13:27:01 -0700 Subject: [PATCH 123/178] Updated Web meeting 2012 09 18 (markdown) --- Web-meeting-2012-09-18.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Web-meeting-2012-09-18.md b/Web-meeting-2012-09-18.md index d4ebe99f..65f538af 100644 --- a/Web-meeting-2012-09-18.md +++ b/Web-meeting-2012-09-18.md @@ -4,7 +4,6 @@ * Berend de Boer * Olivier Ligot * Javier Velilla -* Emmanuel Stapf ## Information @@ -37,11 +36,27 @@ Web meeting using webex * Future tasks * [graphviz-server](https://github.com/EiffelWebFramework/graphviz-server) * Improving Eiffel Web Nino: to support persistent connection, and better concurrency design. - * Provide friendly components to generate HTML (DHTML, HTML5, ...), (coders do not want to learn HTML and CSS) + * Provide friendly components to generate HTML (DHTML, HTML5, ...), (coders do not want to learn HTML and +CSS) * Users feedback, suggestions and requests * ... * Next meeting ## Materials -## Minutes \ No newline at end of file +## Minutes +* swagger: see if we could generate EWF code from a swagger specification +* Jocelyn will publish its attempt to build a CMS with EWF + * CMS demo: ... as announced ... some parts look very like drupal. +* Jocelyn will publish a few in-progress draft libraries +* Javier will focus on graphviz-server and hypermedia API +* Berend may send a short note on how he uses EWF (and generate code from description) +* Jocelyn will try to find time to complete the thread and SCOOP implementation of Eiffel Web Nino +* Olivier will have a closer look at swagger +* EWF will adopt the new WSF_ROUTER design as no-one expressed opposition. Olivier said converting his code is not a big task. Same for other users. +* The current state of EWF/WSF seems to be ok for users, we can focus on libraries on top of EWF/WSF +* We might need an HTML parser, if we want to support HTML as an hypermedia API (maybe we can require XHTML for now) +* No high priority to improve Eiffel Web Nino , for now it is mainly used during development. + +* It seems RESTful + Hypermedia API is the top priority for EWF. + From e48cee9b4abf129dcc3841c73185f663ded7ed2b Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 18 Sep 2012 23:39:45 -0700 Subject: [PATCH 124/178] Updated Projects (markdown) --- Projects.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Projects.md b/Projects.md index ad4f235f..f4309027 100644 --- a/Projects.md +++ b/Projects.md @@ -96,6 +96,7 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, * _Suggested by **Jocelyn**_ * _Supervisor_: * _Suitability_: TODO +* _Status_: started, and open for contribution, collaboration, please contact Jocelyn. * _Description_: Using EWF, Build a simple CMS (Content Management System) framework and then an example. It should provide common features such as: - user management (register, login, lost password -> send email) - page editing From c6dac0384b6e83b6a6c958ce795fd18d2a8af9f3 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Tue, 18 Sep 2012 23:40:52 -0700 Subject: [PATCH 125/178] Updated Projects (markdown) --- Projects.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Projects.md b/Projects.md index f4309027..2aaa7a50 100644 --- a/Projects.md +++ b/Projects.md @@ -226,6 +226,13 @@ If you are a student, don't hesitate to pick one, or even suggest a new project, * This should reuse and improve the "http_client" provided by EWF. Eventually also write the EiffelNet implementation to be independant from cURL * **Requirement**: OAuth client eiffel component +## Build a ESI preprocessor, or proxy +* _Suggested by **Jocelyn**_ +* _Supervisor_: +* _Suitability_: TODO +* _Description_: TODO +* See: http://en.wikipedia.org/wiki/Edge_Side_Includes + ---- # Feel free to add new idea below this line ---- From e12e0b35eef4aa335023bc548b2db34765881fda Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 19 Sep 2012 00:22:50 -0700 Subject: [PATCH 126/178] Created Meetings (markdown) --- Meetings.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Meetings.md diff --git a/Meetings.md b/Meetings.md new file mode 100644 index 00000000..54f5a5d0 --- /dev/null +++ b/Meetings.md @@ -0,0 +1,4 @@ +# Previous and future meetings + +* [Web-meeting-2012-09-18](Web-meeting-2012-09-18) +* For previous meetings, check the ["meeting" topics](https://groups.google.com/forum/?fromgroups=#!tags/eiffel-web-framework/meeting) on the [forum](http://groups.google.com/group/eiffel-web-framework) From e7a06ebc2e79fa10d56af11fef45d1f20261b312 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 19 Sep 2012 00:23:40 -0700 Subject: [PATCH 127/178] Updated Home (markdown) --- Home.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Home.md b/Home.md index 5c47ab7b..962ade01 100644 --- a/Home.md +++ b/Home.md @@ -6,7 +6,7 @@ The official documentation/wiki is located at https://github.com/EiffelWebFramew ## Organization ## - Mailing list: please visit and subscribe to the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) - Most of the topics are discussed on the mailing list (google group). -- For time to time we have web meeting, and less frequently physical meetings that occurs usually during other Eiffel related events. +- For time to time we have [web meetings](meetings), and less frequently [physical meetings](meetings) that occurs usually during other Eiffel related events. ## Documentation ## - to redo From e72ffab2ca5adadd8cdd1b138b6641bb11803bf7 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 19 Sep 2012 00:24:53 -0700 Subject: [PATCH 128/178] Updated Home (markdown) --- Home.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Home.md b/Home.md index 962ade01..31bea4d9 100644 --- a/Home.md +++ b/Home.md @@ -6,7 +6,7 @@ The official documentation/wiki is located at https://github.com/EiffelWebFramew ## Organization ## - Mailing list: please visit and subscribe to the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif) - Most of the topics are discussed on the mailing list (google group). -- For time to time we have [web meetings](meetings), and less frequently [physical meetings](meetings) that occurs usually during other Eiffel related events. +- For time to time we have [[web meetings|meetings]], and less frequently [[physical meetings|meetings]] that occurs usually during other Eiffel related events. ## Documentation ## - to redo From 1dc6ff6df1fe295f89545f777a18c873104bdea6 Mon Sep 17 00:00:00 2001 From: jocelyn Date: Wed, 19 Sep 2012 00:25:16 -0700 Subject: [PATCH 129/178] Updated Meetings (markdown) --- Meetings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Meetings.md b/Meetings.md index 54f5a5d0..a75a124f 100644 --- a/Meetings.md +++ b/Meetings.md @@ -1,4 +1,4 @@ # Previous and future meetings -* [Web-meeting-2012-09-18](Web-meeting-2012-09-18) +* [[Web-meeting: 2012-09-18|Web-meeting-2012-09-18]] * For previous meetings, check the ["meeting" topics](https://groups.google.com/forum/?fromgroups=#!tags/eiffel-web-framework/meeting) on the [forum](http://groups.google.com/group/eiffel-web-framework) From 92cbf48b49ba74788b6b07d873972cf6ec865f19 Mon Sep 17 00:00:00 2001 From: oligot Date: Mon, 8 Oct 2012 03:38:12 -0700 Subject: [PATCH 130/178] Updated Projects new suggestions (markdown) --- Projects-new-suggestions.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Projects-new-suggestions.md b/Projects-new-suggestions.md index 23e0a613..2d5535bd 100644 --- a/Projects-new-suggestions.md +++ b/Projects-new-suggestions.md @@ -17,4 +17,13 @@ For any entry, please use this template * _Description_: Build a Swagger Eiffel implementation * _References_: http://swagger.wordnik.com/ ----- \ No newline at end of file +---- + +## Add support for Apache logging +* _Suggested by **Olivier**_ +* _Description_: Be able to log using the Apache Common Log Format +* _References_: + - http://httpd.apache.org/docs/2.2/logs.html#common + - http://www.w3.org/Daemon/User/Config/Logging.html#common-logfile-format + +---- From c23bf7a05d0c41956f464b3454115b1ed0ad9d78 Mon Sep 17 00:00:00 2001 From: oligot Date: Thu, 22 Nov 2012 04:30:08 -0800 Subject: [PATCH 131/178] Created Useful links (markdown) --- Useful-links.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Useful-links.md diff --git a/Useful-links.md b/Useful-links.md new file mode 100644 index 00000000..5389d44b --- /dev/null +++ b/Useful-links.md @@ -0,0 +1,4 @@ +## ETags + +* http://www.mnot.net/blog/2007/08/07/etags +* http://bitworking.org/news/150/REST-Tip-Deep-etags-give-you-more-benefits \ No newline at end of file From 2b92ba9e6267e70b4bf4edd15cfbdefbcb07003a Mon Sep 17 00:00:00 2001 From: oligot Date: Thu, 22 Nov 2012 11:28:17 -0800 Subject: [PATCH 132/178] Updated Useful links (markdown) --- Useful-links.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Useful-links.md b/Useful-links.md index 5389d44b..29c810b7 100644 --- a/Useful-links.md +++ b/Useful-links.md @@ -1,3 +1,13 @@ +## Eiffel + +* http://www.scoop.it/t/eiffel-resources +* http://www.scoop.it/t/eiffel + +## Hypermedia + +* http://www.scoop.it/t/hyper-media-apis +* http://www.scoop.it/t/hypermedia-api + ## ETags * http://www.mnot.net/blog/2007/08/07/etags From 0eff04c8472a66f3b7cf58bbd40a33bdcb70326f Mon Sep 17 00:00:00 2001 From: oligot Date: Sun, 3 Feb 2013 04:10:46 -0800 Subject: [PATCH 133/178] Add support for Apache logging: done --- Projects-new-suggestions.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Projects-new-suggestions.md b/Projects-new-suggestions.md index 2d5535bd..6093b9c9 100644 --- a/Projects-new-suggestions.md +++ b/Projects-new-suggestions.md @@ -18,12 +18,3 @@ For any entry, please use this template * _References_: http://swagger.wordnik.com/ ---- - -## Add support for Apache logging -* _Suggested by **Olivier**_ -* _Description_: Be able to log using the Apache Common Log Format -* _References_: - - http://httpd.apache.org/docs/2.2/logs.html#common - - http://www.w3.org/Daemon/User/Config/Logging.html#common-logfile-format - ----- From 0efcd3cd070de44196ba69792aeed9912d1ebe15 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 4 Jul 2013 07:03:22 -0700 Subject: [PATCH 134/178] Created Doc_Index (mediawiki) --- Doc_Index.mediawiki | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Doc_Index.mediawiki diff --git a/Doc_Index.mediawiki b/Doc_Index.mediawiki new file mode 100644 index 00000000..b9db9b15 --- /dev/null +++ b/Doc_Index.mediawiki @@ -0,0 +1,7 @@ += Eiffel Web Framework = +Framework to build web applications in Eiffel + +Menu :: [[Doc_Getting Started|Getting Started]] :: [[Doc_Community|Community]] + +[http://github.com/EiffelWebFramework/EWF/zipball/ Download Current] +[http://github.com/EiffelWebFramework/EWF/zipball/release-0.3 Download v0.3] \ No newline at end of file From e4f495b2825b010ccf263a0650a70c2c4bcfca5a Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 4 Jul 2013 07:04:18 -0700 Subject: [PATCH 135/178] Created Doc_Getting_Started (mediawiki) --- Doc_Getting_Started.mediawiki | 1 + 1 file changed, 1 insertion(+) create mode 100644 Doc_Getting_Started.mediawiki diff --git a/Doc_Getting_Started.mediawiki b/Doc_Getting_Started.mediawiki new file mode 100644 index 00000000..88593f1e --- /dev/null +++ b/Doc_Getting_Started.mediawiki @@ -0,0 +1 @@ += Getting Started = \ No newline at end of file From 60a80209dc3ff19e2f85508986bcdd47b181ffc0 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 4 Jul 2013 07:04:51 -0700 Subject: [PATCH 136/178] Updated Doc_Index (mediawiki) --- Doc_Index.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc_Index.mediawiki b/Doc_Index.mediawiki index b9db9b15..bb498aea 100644 --- a/Doc_Index.mediawiki +++ b/Doc_Index.mediawiki @@ -1,7 +1,7 @@ = Eiffel Web Framework = Framework to build web applications in Eiffel -Menu :: [[Doc_Getting Started|Getting Started]] :: [[Doc_Community|Community]] +Menu :: [[Doc_Getting_Started|Getting Started]] :: [[Doc_Community|Community]] [http://github.com/EiffelWebFramework/EWF/zipball/ Download Current] [http://github.com/EiffelWebFramework/EWF/zipball/release-0.3 Download v0.3] \ No newline at end of file From ed1f899534263da5fac5b556ab516405b6647b8e Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 4 Jul 2013 07:05:20 -0700 Subject: [PATCH 137/178] Updated Doc_Index (mediawiki) --- Doc_Index.mediawiki | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc_Index.mediawiki b/Doc_Index.mediawiki index bb498aea..c88b0bc9 100644 --- a/Doc_Index.mediawiki +++ b/Doc_Index.mediawiki @@ -3,5 +3,5 @@ Framework to build web applications in Eiffel Menu :: [[Doc_Getting_Started|Getting Started]] :: [[Doc_Community|Community]] -[http://github.com/EiffelWebFramework/EWF/zipball/ Download Current] -[http://github.com/EiffelWebFramework/EWF/zipball/release-0.3 Download v0.3] \ No newline at end of file +[ [http://github.com/EiffelWebFramework/EWF/zipball/ Download Current] ] +[ [http://github.com/EiffelWebFramework/EWF/zipball/release-0.3 Download v0.3] ] \ No newline at end of file From 917388b99e0cb8b5ecab97b57cffbc5fa9aeed2f Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 4 Jul 2013 07:07:00 -0700 Subject: [PATCH 138/178] Updated Doc_Index (mediawiki) --- Doc_Index.mediawiki | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc_Index.mediawiki b/Doc_Index.mediawiki index c88b0bc9..90016448 100644 --- a/Doc_Index.mediawiki +++ b/Doc_Index.mediawiki @@ -1,7 +1,7 @@ +Menu :: [[Doc_Getting_Started|Getting Started]] :: [[Doc_Community|Community]] + = Eiffel Web Framework = Framework to build web applications in Eiffel -Menu :: [[Doc_Getting_Started|Getting Started]] :: [[Doc_Community|Community]] - [ [http://github.com/EiffelWebFramework/EWF/zipball/ Download Current] ] [ [http://github.com/EiffelWebFramework/EWF/zipball/release-0.3 Download v0.3] ] \ No newline at end of file From e20f45b2c3bdb134fd7a035b654ac884ab4069a1 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 4 Jul 2013 07:08:54 -0700 Subject: [PATCH 139/178] Updated Doc_Getting_Started (mediawiki) --- Doc_Getting_Started.mediawiki | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Doc_Getting_Started.mediawiki b/Doc_Getting_Started.mediawiki index 88593f1e..50579c63 100644 --- a/Doc_Getting_Started.mediawiki +++ b/Doc_Getting_Started.mediawiki @@ -1 +1,24 @@ -= Getting Started = \ No newline at end of file +Menu :: [[Doc_Getting_Started|Getting Started]] :: [[Doc_Community|Community]] + += Getting Started = +This page will help you to get started with EWF. We will first see how to install EWF and then how to compile and run the venerable Hello World example. + +== Installation == +=== EiffelStudio 7.2 === +EWF is already included in EiffelStudio 7.2: you don't have to do anything in this case! This is the recommanded solution if you are a new developer or are new to Eiffel. + +=== Other EiffelStudio versions === +If you have another version of EiffelStudio than 7.2, you have to + +* dowload EWF +* create a directory where you will put your custum Eiffel libraries +* extract EWF in the newly created directory +* define the environment variable EIFFEL_LIBRARY to point to the newly created directory + +=== Source code === +The source code is available on Github. You can get it by running the command: + +: git clone git://github.com/EiffelWebFramework/EWF.git + + + From 2d373cab5b77957b7efa8992b7a4eb51be5d48a2 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 4 Jul 2013 07:25:44 -0700 Subject: [PATCH 140/178] Updated Doc_Getting_Started (mediawiki) --- Doc_Getting_Started.mediawiki | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/Doc_Getting_Started.mediawiki b/Doc_Getting_Started.mediawiki index 50579c63..d2692f4b 100644 --- a/Doc_Getting_Started.mediawiki +++ b/Doc_Getting_Started.mediawiki @@ -18,7 +18,40 @@ If you have another version of EiffelStudio than 7.2, you have to === Source code === The source code is available on Github. You can get it by running the command: -: git clone git://github.com/EiffelWebFramework/EWF.git +git clone git://github.com/EiffelWebFramework/EWF.git +== Hello World == +The hello world example is located in the directory $ISE_EIFFEL/contrib/examples/web/ewf/simple. Just double click on the simple.ecf file and select the simple target or if you prefer the command line, run the command: +estudio -config simple.ecf -target simple +Once the project is compiled, we will adapt the root class to point to port number 9090. +'''Note''': By default, the application listens on port 80, which is often already used by standard webservers (Apache, nginx, ...). Moreover, on Linux, ports below 1024 can only be opened by root. + +To do this, we will redefine the feature initialize as follows: + + +class + APPLICATION + +inherit + WSF_DEFAULT_SERVICE + redefine + initialize + end + +create + make_and_launch + +feature {NONE} -- Initialization + + initialize + -- Initialize current service + do + set_service_option ("port", 9090) + end +end + + +After one more compile, you can now launch the application and point your browser to [http://localhost:9090]. +You should now see a simple page with Hello World. \ No newline at end of file From 717b0f7ba8c3cee6c73be630e576f5b6c9421090 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 4 Jul 2013 07:27:51 -0700 Subject: [PATCH 141/178] Updated Doc_Getting_Started (mediawiki) --- Doc_Getting_Started.mediawiki | 40 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Doc_Getting_Started.mediawiki b/Doc_Getting_Started.mediawiki index d2692f4b..f3eebb63 100644 --- a/Doc_Getting_Started.mediawiki +++ b/Doc_Getting_Started.mediawiki @@ -31,26 +31,26 @@ Once the project is compiled, we will adapt the root class to point to port numb To do this, we will redefine the feature initialize as follows: -class - APPLICATION - -inherit - WSF_DEFAULT_SERVICE - redefine - initialize - end - -create - make_and_launch - -feature {NONE} -- Initialization - - initialize - -- Initialize current service - do - set_service_option ("port", 9090) - end -end + class + APPLICATION + + inherit + WSF_DEFAULT_SERVICE + redefine + initialize + end + + create + make_and_launch + + feature {NONE} -- Initialization + + initialize + -- Initialize current service + do + set_service_option ("port", 9090) + end + end After one more compile, you can now launch the application and point your browser to [http://localhost:9090]. From 2d795eb3c1d2b9abb885011abf4fe2da6470bcda Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 4 Jul 2013 07:28:09 -0700 Subject: [PATCH 142/178] Updated Doc_Getting_Started (mediawiki) --- Doc_Getting_Started.mediawiki | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc_Getting_Started.mediawiki b/Doc_Getting_Started.mediawiki index f3eebb63..a3d22099 100644 --- a/Doc_Getting_Started.mediawiki +++ b/Doc_Getting_Started.mediawiki @@ -30,7 +30,6 @@ Once the project is compiled, we will adapt the root class to point to port numb To do this, we will redefine the feature initialize as follows: - class APPLICATION @@ -51,7 +50,7 @@ To do this, we will redefine the feature initialize as follows: set_service_option ("port", 9090) end end - + After one more compile, you can now launch the application and point your browser to [http://localhost:9090]. You should now see a simple page with Hello World. \ No newline at end of file From 6dee9e85b557fd880529b5f64de19fe24d95cff5 Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Thu, 4 Jul 2013 07:28:37 -0700 Subject: [PATCH 143/178] Updated Doc_Getting_Started (mediawiki) --- Doc_Getting_Started.mediawiki | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc_Getting_Started.mediawiki b/Doc_Getting_Started.mediawiki index a3d22099..550862d8 100644 --- a/Doc_Getting_Started.mediawiki +++ b/Doc_Getting_Started.mediawiki @@ -30,6 +30,7 @@ Once the project is compiled, we will adapt the root class to point to port numb To do this, we will redefine the feature initialize as follows: + class APPLICATION From 78ff0134c75ca91bbd34ec02bec54eee3dd54e5d Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 03:27:42 -0700 Subject: [PATCH 144/178] Created Using the policy driven framework (markdown) --- Using-the-policy-driven-framework.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 Using-the-policy-driven-framework.md diff --git a/Using-the-policy-driven-framework.md b/Using-the-policy-driven-framework.md new file mode 100644 index 00000000..a0e5836d --- /dev/null +++ b/Using-the-policy-driven-framework.md @@ -0,0 +1,9 @@ +# Using the policy driven framework + +## Introduction + +The aim of the policy-driven framework is to allow authors of web-servers to concentrate on the business logic (e.g., in the case of a GET request, generating the content), without having to worry about the details of the HTTP protocol (such as headers and response codes). However, there are so many possibilities in the HTTP protocol, that it is impossible to correctly guess what to do in all cases. Therefore the author has to supply policy decisions to the framework, in areas such as caching decisions. These are implemented as a set of deferred classes for which the author needs to provide effective implementations. + +## Mapping the URI space + +The authors first task is to decide which URIs the server will respond to (we do this using [URI templates](http://tools.ietf.org/html/rfc6570) ) and which methods are supported for each template.This is done in the class that that defines the service (which is often the root class for the application). This class must be a descendant of WSF_ROUTED_SKELETON_SERVICE. \ No newline at end of file From 7dd36014cc987575b1c964efd80effa42b05e9cb Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 03:56:52 -0700 Subject: [PATCH 145/178] Updated Using the policy driven framework (markdown) --- Using-the-policy-driven-framework.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Using-the-policy-driven-framework.md b/Using-the-policy-driven-framework.md index a0e5836d..077ddfd2 100644 --- a/Using-the-policy-driven-framework.md +++ b/Using-the-policy-driven-framework.md @@ -4,6 +4,12 @@ The aim of the policy-driven framework is to allow authors of web-servers to concentrate on the business logic (e.g., in the case of a GET request, generating the content), without having to worry about the details of the HTTP protocol (such as headers and response codes). However, there are so many possibilities in the HTTP protocol, that it is impossible to correctly guess what to do in all cases. Therefore the author has to supply policy decisions to the framework, in areas such as caching decisions. These are implemented as a set of deferred classes for which the author needs to provide effective implementations. +We aim to provide unconditional compliance [See HTTP/1.1 specification](http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html#sec1) for you. + ## Mapping the URI space -The authors first task is to decide which URIs the server will respond to (we do this using [URI templates](http://tools.ietf.org/html/rfc6570) ) and which methods are supported for each template.This is done in the class that that defines the service (which is often the root class for the application). This class must be a descendant of WSF_ROUTED_SKELETON_SERVICE. \ No newline at end of file +The authors first task is to decide which URIs the server will respond to (we do this using [URI templates](http://tools.ietf.org/html/rfc6570) ) and which methods are supported for each template.This is done in the class that that defines the service (which is often the root class for the application). This class must be a descendant of WSF_ROUTED_SKELETON_SERVICE. Throughout this tutorial, we will refer to the restbucksCRUD example application, which can be found in the EWF distribution in the examples directory. It's root class, RESTBUCKS_SERVER, inherits from WSF_ROUTED_SKELETON_SERVICE, as well as WSF_DEFAULT_SERVICE. The latter class means that you must specify in the ECF which connector you will use by default.This means you can easily change connectors just by changing the ECF and recompiling. + +### Declaring your URI templates + +In order to map your URI space to handlers (which you will write), you need to implement the routine setup_router. You can see in the example that the ORDER_HANDLER handler is associated with two URI templates. The URI /order is associated with the POST method (only). Any requests to /order with the GET method (or any other method) will result in an automatically generated compliant response being sent on your behalf to the client. The other principle methods (you get compliant responses to the HEAD method for free whenever you allow the GET method) are associated with the URI template /order/{orderid}. Here, orderid is a template variable. It's value for any given request is provided to your application as {WSF_REQUEST}.path_parameter ("orderid"). If the client passes a URI of /order/21, then you will see the value 21. If the client passes /order/fred, you will see the value fred. But if the client passes /order/21/new, he will see a compliant error response generated by the framework. \ No newline at end of file From b55f3636515c6db7dc889b3ef36426d90d2816a6 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 05:30:02 -0700 Subject: [PATCH 146/178] Updated Using the policy driven framework (markdown) --- Using-the-policy-driven-framework.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Using-the-policy-driven-framework.md b/Using-the-policy-driven-framework.md index 077ddfd2..115804e0 100644 --- a/Using-the-policy-driven-framework.md +++ b/Using-the-policy-driven-framework.md @@ -12,4 +12,13 @@ The authors first task is to decide which URIs the server will respond to (we do ### Declaring your URI templates -In order to map your URI space to handlers (which you will write), you need to implement the routine setup_router. You can see in the example that the ORDER_HANDLER handler is associated with two URI templates. The URI /order is associated with the POST method (only). Any requests to /order with the GET method (or any other method) will result in an automatically generated compliant response being sent on your behalf to the client. The other principle methods (you get compliant responses to the HEAD method for free whenever you allow the GET method) are associated with the URI template /order/{orderid}. Here, orderid is a template variable. It's value for any given request is provided to your application as {WSF_REQUEST}.path_parameter ("orderid"). If the client passes a URI of /order/21, then you will see the value 21. If the client passes /order/fred, you will see the value fred. But if the client passes /order/21/new, he will see a compliant error response generated by the framework. \ No newline at end of file +In order to map your URI space to handlers (which you will write), you need to implement the routine setup_router. You can see in the example that the ORDER_HANDLER handler is associated with two URI templates. The URI /order is associated with the POST method (only). Any requests to /order with the GET method (or any other method) will result in an automatically generated compliant response being sent on your behalf to the client. The other principle methods (you get compliant responses to the HEAD method for free whenever you allow the GET method) are associated with the URI template /order/{orderid}. Here, orderid is a template variable. It's value for any given request is provided to your application as {WSF_REQUEST}.path_parameter ("orderid"). If the client passes a URI of /order/21, then you will see the value 21. If the client passes /order/fred, you will see the value fred. But if the client passes /order/21/new, he will see a compliant error response generated by the framework. + +## Declaring your policy in responding to OPTIONS + +WSF_ROUTED_SKELETON_SERVICE inherits from WSF_SYSTEM_OPTIONS_ACCESS_POLICY. This policy declares that the framework will provide a compliant default response to OPTIONS * requests. If you prefer to not respond to OPTIONS * requests (and I am doubtful if it is fully compliant to make that choice), then you can redefine +is_system_options_forbidden. + +## Declaring your policy on requiring use of a proxy server + +WSF_ROUTED_SKELETON_SERVICE also inherits from WSF_PROXY_USE_POLICY. This determines if the server will require clients to use a proxy server. By default, it will do so for HTTP/1.0 clients. This is a sensible default, as the framework assumes an HTTP/1.1 client throughout. If you are sure that you will only ever have HTTP/1.1 clients, then you can instead inherit from WSF_NO_PROXY_POLICY, as RESTBUCKS_SERVER does. If not, then you need to implement proxy_server. From 0c4a410ac0d118a9596ec0dcb948959a3db89d8a Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 05:51:11 -0700 Subject: [PATCH 147/178] Created Writing the handlers (markdown) --- Writing-the-handlers.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Writing-the-handlers.md diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md new file mode 100644 index 00000000..b59fbd38 --- /dev/null +++ b/Writing-the-handlers.md @@ -0,0 +1,3 @@ +# Writing the handlers + +Now you have to implement each handler. You need to inherit from WSF_SKELETON_HANDLER (as ORDER_HANDLER does). This involves implementing a lot of deferred routines. There are other routines for which default implementations are provided, which you might want to override. \ No newline at end of file From 84c3039806c5ae74b0856e7f9fc0ddc40b47d507 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 05:51:54 -0700 Subject: [PATCH 148/178] Updated Using the policy driven framework (markdown) --- Using-the-policy-driven-framework.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Using-the-policy-driven-framework.md b/Using-the-policy-driven-framework.md index 115804e0..2999ec9a 100644 --- a/Using-the-policy-driven-framework.md +++ b/Using-the-policy-driven-framework.md @@ -22,3 +22,5 @@ is_system_options_forbidden. ## Declaring your policy on requiring use of a proxy server WSF_ROUTED_SKELETON_SERVICE also inherits from WSF_PROXY_USE_POLICY. This determines if the server will require clients to use a proxy server. By default, it will do so for HTTP/1.0 clients. This is a sensible default, as the framework assumes an HTTP/1.1 client throughout. If you are sure that you will only ever have HTTP/1.1 clients, then you can instead inherit from WSF_NO_PROXY_POLICY, as RESTBUCKS_SERVER does. If not, then you need to implement proxy_server. + +Next you have to [write your handler(s)](./Writing-the-handlers) \ No newline at end of file From bf0a8e8efbb7a0f3dd83b52c79645f2ff01fefb8 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 05:57:49 -0700 Subject: [PATCH 149/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index b59fbd38..d1fd9324 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -1,3 +1,11 @@ # Writing the handlers -Now you have to implement each handler. You need to inherit from WSF_SKELETON_HANDLER (as ORDER_HANDLER does). This involves implementing a lot of deferred routines. There are other routines for which default implementations are provided, which you might want to override. \ No newline at end of file +Now you have to implement each handler. You need to inherit from WSF_SKELETON_HANDLER (as ORDER_HANDLER does). This involves implementing a lot of deferred routines. There are other routines for which default implementations are provided, which you might want to override. This applies to both routines defined in this class, and those declared in the three policy classes from which it inherits. + +## Implementing the routines declared directly in WSF_SKELETON_HANDLER + +TODO + +## Implementing the policies + +TODO \ No newline at end of file From f3849679e896771fa5c531c2957925c5fdf6d301 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 06:00:37 -0700 Subject: [PATCH 150/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index d1fd9324..61be5110 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -8,4 +8,8 @@ TODO ## Implementing the policies +* WSF_OPTIONS_POLICY +* WSF_PREVIOUS_POLICY +* WSF_CACHING_POLICY + TODO \ No newline at end of file From 45fd51b4b5de38887850ca28b4bc9842ab7496b2 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 06:02:24 -0700 Subject: [PATCH 151/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 61be5110..081c4a59 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -8,7 +8,7 @@ TODO ## Implementing the policies -* WSF_OPTIONS_POLICY +* [WSF_OPTIONS_POLICY](edit this) * WSF_PREVIOUS_POLICY * WSF_CACHING_POLICY From 7bc09bda8fb84d7d359b842246819b9b28e0ade5 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 06:02:42 -0700 Subject: [PATCH 152/178] Created WSF_OPTIONS_POLICY (markdown) --- WSF_OPTIONS_POLICY.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 WSF_OPTIONS_POLICY.md diff --git a/WSF_OPTIONS_POLICY.md b/WSF_OPTIONS_POLICY.md new file mode 100644 index 00000000..30404ce4 --- /dev/null +++ b/WSF_OPTIONS_POLICY.md @@ -0,0 +1 @@ +TODO \ No newline at end of file From 33d523e5bf2beb0ef52323df780a1fbe9745581e Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 06:03:13 -0700 Subject: [PATCH 153/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 081c4a59..598a05fc 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -8,7 +8,7 @@ TODO ## Implementing the policies -* [WSF_OPTIONS_POLICY](edit this) +* [WSF_OPTIONS_POLICY](./WSF_OPTIONS_POLICY) * WSF_PREVIOUS_POLICY * WSF_CACHING_POLICY From 090e294f1060cd5f3db82fdd231f75e86058bbfa Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 06:06:15 -0700 Subject: [PATCH 154/178] Updated WSF_OPTIONS_POLICY (markdown) --- WSF_OPTIONS_POLICY.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WSF_OPTIONS_POLICY.md b/WSF_OPTIONS_POLICY.md index 30404ce4..2056c430 100644 --- a/WSF_OPTIONS_POLICY.md +++ b/WSF_OPTIONS_POLICY.md @@ -1 +1,3 @@ -TODO \ No newline at end of file +# Implementing routines in WSF_OPTIONS_POLICY + +This class provides a default response to OPTIONS requests other than OPTIONS *. So you don't have to do anything. The default response just includes the mandatory Allow headers for all the methods that are allowed for the request URI. if you want to include a body text, or additional header, then you should redefine this routine. \ No newline at end of file From 7815557f840514613ac37514e2349169989d788f Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 06:14:24 -0700 Subject: [PATCH 155/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 598a05fc..2021f1ae 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -9,7 +9,7 @@ TODO ## Implementing the policies * [WSF_OPTIONS_POLICY](./WSF_OPTIONS_POLICY) -* WSF_PREVIOUS_POLICY +* [WSF_PREVIOUS_POLICY](./WSF_PREVIOUS_POLICY) * WSF_CACHING_POLICY TODO \ No newline at end of file From c261f02c8472d6217a9a17fe7a2a96ba9651b6f6 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 06:24:45 -0700 Subject: [PATCH 156/178] Created Wsf previous policy (markdown) --- Wsf-previous-policy.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Wsf-previous-policy.md diff --git a/Wsf-previous-policy.md b/Wsf-previous-policy.md new file mode 100644 index 00000000..37c965c5 --- /dev/null +++ b/Wsf-previous-policy.md @@ -0,0 +1,20 @@ +# Implementing WSF_PREVIOUS_POLICY + +This class provides routines which enable the programmer to encode knowledge about resources that have moved (either temporarily, or permanently), or have been permanently removed. There are four routines, but only one is actually deferred. + +## resource_previously_existed + +By default, this routine says that currently doesn't exist, never has existed. You need to redefine this routine to return True for any URIs that you want to indicate used to exist, and either no longer do so, or have moved to another location. + +## resource_moved_permanently + +If you have indicated that a resource previously existed, then it may have moved permanently, temporarily, or just ceased to exist. In the first case, you need to redefine this routine to return True for such a resource. +## resource_moved_temporarily + +If you have indicated that a resource previously existed, then it may have moved permanently, temporarily, or just ceased to exist. In the second case, you need to redefine this routine to return True for such a resource. + +## previous_location + +You need to implement this routine. It should provide the locations where a resource has moved to. There must be at least one such location. If more than one is provided, then the first one is considered primary. + +If the preconditions for this routine are never met (as is the case by default), then just return an empty list. \ No newline at end of file From 3b517d3c53d1bd3836f84e25305c3c5c343d6d6f Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 06:25:31 -0700 Subject: [PATCH 157/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 2021f1ae..256296e2 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -10,6 +10,4 @@ TODO * [WSF_OPTIONS_POLICY](./WSF_OPTIONS_POLICY) * [WSF_PREVIOUS_POLICY](./WSF_PREVIOUS_POLICY) -* WSF_CACHING_POLICY - -TODO \ No newline at end of file +* [WSF_CACHING_POLICY](./WSF_CACHING_POLICY) From 259815467c86758253c6ec3de84592910ea607dd Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 07:05:24 -0700 Subject: [PATCH 158/178] Created Wsf caching policy (markdown) --- Wsf-caching-policy.md | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Wsf-caching-policy.md diff --git a/Wsf-caching-policy.md b/Wsf-caching-policy.md new file mode 100644 index 00000000..e2c5d6ae --- /dev/null +++ b/Wsf-caching-policy.md @@ -0,0 +1,52 @@ +# Implementing WSF_CACHING_POLICY + +This class contains a large number of routines, some of which have sensible defaults. + +## age + +This is used to generate a **Cache-Control: max-age** header. It says how old the response can before a cache will consider it stale (and therefore will need to revalidate with the server). Common values are zero (always consider it stale) and Never_expires (never always mean up to one year) and 1440 (one day). + +## shared_age + +This defaults to the same as age, so you only have to redefine it if you want a different value. If different from age, then we generate a **Cache-Control: s-max-age** header. This applies to shared caches only. Otherwise it has the same meaning as age. This overrides the value specified in age for shared caches. + +## http_1_0_age + +This generates an **Expires** header, and has the same meaning as age, but is understood by HTTP/1.0 caches. By default it has the same value as age. You only need to redefine this if you want to treat HTTP/1.0 caches differently (you might not trust them so well, so you might want to return 0 here). + +## is_freely_cacheable + +This routine says whether a shared cache can use this response for all client. If True, then it generates a **Cache-Control: public** header. If your data is at all sensitive, then you want to return False here. + +## is_transformable + +Non-transparent proxies are allowed to make some modifications to headers. If your application relies on this _not_ happening, then you want to return False here. This is the default, so you don't have to do anything. This means a **Cache-Control: no-transform** header will be generated. +But most applications can return True. + +## must_revalidate + +Some clients request that their private cache ignores server expiry times (and so freely reuse stale responses). If you want to force revalidation anyway in such circumstances, then redefine to return True. In which case, we generate a **Cache-Control: must-revalidate** header. + +## must_proxy_revalidate + +This is the same as must_revalidate, but only applies to shared caches that are configured to serve stale responses. If you redefine to return True, then we generate a **Cache-Control: proxy-revalidate** header. + +## private_headers + +This is used to indicate that parts (or all) of a response are considered private to a single user, and should not be freely served from a shared cache. You must implement this routine. Your choices are: + +1. Return Void. None of the response is considered private. +1. Return and empty list. All of the response is considered private. +1. Return a list of header names. + +If you don't return Void, then a **Cache-Control: private** header will be generated. + +## non_cacheable_headers + +This is similar to private_headers, and you have the same three choices. the difference is that it is a list of headers (or the whole response) that will not be sent from a cache without revalidation. + +If you don't return Void, then a **Cache-Control: no-cache** header will be generated. + +## is_sensitive + +Is the response to be considered of a sensitive nature? If so, then it will not be archived from a cache. We generate a **Cache-Control: no-store** header. \ No newline at end of file From ce04737d46b5eab52818125c2444d42328ed82c8 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 07:18:35 -0700 Subject: [PATCH 159/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 256296e2..5834c9ed 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -4,7 +4,17 @@ Now you have to implement each handler. You need to inherit from WSF_SKELETON_HA ## Implementing the routines declared directly in WSF_SKELETON_HANDLER -TODO +### is_chunking + +HTTP/1.1 supports streaming responses (and providing you have configured your server to use a proxy server in WSF_PROXY_USE_POLICY, this framework guarantees you have an HTTP/1.1 client to deal with). It is up to you whether or not you choose to make use of it. If so, then you have to serve the response one chunk at a time (but you could generate it all at once, and slice it up as you go). In this routine you just say whether or not you will be doing this. So the framework n=knows which other routines to call. + +## includes_response_entity + +The response to a DELETE, PUT or POST will include HTTP headers. It may or may not include a body. It is up to you, and this is where you tell the framework. + +## conneg + +[The HTTP/1.1 specification](http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1) defines server-driven content negotiation. Based on the Accept* headers in the request, we can determine whether we have a format for the response entity that is acceptable to the client. You need to indicate what formats you support. The framework does the rest. Normally you will have the same options for all requests, in which case you can use a once object. ## Implementing the policies From 9395e31c5343b3fee2929e4520537d833c98e8b7 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 08:50:31 -0700 Subject: [PATCH 160/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 45 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 5834c9ed..8f958854 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -16,8 +16,51 @@ The response to a DELETE, PUT or POST will include HTTP headers. It may or may n [The HTTP/1.1 specification](http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1) defines server-driven content negotiation. Based on the Accept* headers in the request, we can determine whether we have a format for the response entity that is acceptable to the client. You need to indicate what formats you support. The framework does the rest. Normally you will have the same options for all requests, in which case you can use a once object. +## mime_types_supported + +Here you need to indicate which media types you support for responses. One of the entries must be passed to the creation routine for conneg. + +## languages_supported + +Here you need to indicate which languages you support for responses. One of the entries must be passed to the creation routine for conneg. + + +## charsets_supported + +Here you need to indicate which character sets you support for responses. One of the entries must be passed to the creation routine for conneg. + + +## encodings_supported + +Here you need to indicate which compression encodings you support for responses. One of the entries must be passed to the creation routine for conneg. + +## additional_variant_headers + +The framework will write a Vary header if conneg indicates that different formats are supported. This warns caches that they may not be able to use a cached response if the Accept* headers in the request differ. If the author knows that the response may be affected by other request headers in addition to these, then they must be indicated here, so they can be included in a Vary header with the response. + +## predictable_response + +If the response may vary in other ways not predictable from the request headers, then redefine this routine to return True. In that case we will generate a Vary: * header to inform the cache that the response is not necessarily repeatable. + +## matching_etag + +An **ETag** header is a kind of message digest. Clients can use etags to avoid re-fetching responses for unchanged resources, or to avoid updating a resource that may have changed since the client last updated it. +You must implement this routine to test for matches **if and only if** you return non-Void responses for the etag routine. + +## etag + +You are strongly encouraged to return non-Void for this routine. See [Validation Model](http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3) for more details. + +## modified_since + +You need to implement this. If you do not have information about when a resource was last modified, then return True as a precaution. Of course, you return false for a static resource. + +## treat_as_moved_permanently + +This routine when a PUT request is made to a resource that does not exist. See [PUT](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6) in the HTTP/1.1 specification for why you might want to return zero. + ## Implementing the policies * [WSF_OPTIONS_POLICY](./WSF_OPTIONS_POLICY) * [WSF_PREVIOUS_POLICY](./WSF_PREVIOUS_POLICY) -* [WSF_CACHING_POLICY](./WSF_CACHING_POLICY) +* [WSF_CACHING_POLICY](./WSF_CACHING_POLICY) \ No newline at end of file From a552b8fcfa3fd27c82787df896e9811fb3a96633 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 09:13:56 -0700 Subject: [PATCH 161/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 8f958854..e82961ec 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -8,54 +8,54 @@ Now you have to implement each handler. You need to inherit from WSF_SKELETON_HA HTTP/1.1 supports streaming responses (and providing you have configured your server to use a proxy server in WSF_PROXY_USE_POLICY, this framework guarantees you have an HTTP/1.1 client to deal with). It is up to you whether or not you choose to make use of it. If so, then you have to serve the response one chunk at a time (but you could generate it all at once, and slice it up as you go). In this routine you just say whether or not you will be doing this. So the framework n=knows which other routines to call. -## includes_response_entity +### includes_response_entity The response to a DELETE, PUT or POST will include HTTP headers. It may or may not include a body. It is up to you, and this is where you tell the framework. -## conneg +### conneg [The HTTP/1.1 specification](http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1) defines server-driven content negotiation. Based on the Accept* headers in the request, we can determine whether we have a format for the response entity that is acceptable to the client. You need to indicate what formats you support. The framework does the rest. Normally you will have the same options for all requests, in which case you can use a once object. -## mime_types_supported +### mime_types_supported Here you need to indicate which media types you support for responses. One of the entries must be passed to the creation routine for conneg. -## languages_supported +### languages_supported Here you need to indicate which languages you support for responses. One of the entries must be passed to the creation routine for conneg. -## charsets_supported +### charsets_supported Here you need to indicate which character sets you support for responses. One of the entries must be passed to the creation routine for conneg. -## encodings_supported +### encodings_supported Here you need to indicate which compression encodings you support for responses. One of the entries must be passed to the creation routine for conneg. -## additional_variant_headers +### additional_variant_headers The framework will write a Vary header if conneg indicates that different formats are supported. This warns caches that they may not be able to use a cached response if the Accept* headers in the request differ. If the author knows that the response may be affected by other request headers in addition to these, then they must be indicated here, so they can be included in a Vary header with the response. -## predictable_response +### predictable_response If the response may vary in other ways not predictable from the request headers, then redefine this routine to return True. In that case we will generate a Vary: * header to inform the cache that the response is not necessarily repeatable. -## matching_etag +### matching_etag An **ETag** header is a kind of message digest. Clients can use etags to avoid re-fetching responses for unchanged resources, or to avoid updating a resource that may have changed since the client last updated it. You must implement this routine to test for matches **if and only if** you return non-Void responses for the etag routine. -## etag +### etag You are strongly encouraged to return non-Void for this routine. See [Validation Model](http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3) for more details. -## modified_since +### modified_since You need to implement this. If you do not have information about when a resource was last modified, then return True as a precaution. Of course, you return false for a static resource. -## treat_as_moved_permanently +### treat_as_moved_permanently This routine when a PUT request is made to a resource that does not exist. See [PUT](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6) in the HTTP/1.1 specification for why you might want to return zero. From 10caa4c1dfb17ffef608729b3428a7ae5b9f897f Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 09:48:38 -0700 Subject: [PATCH 162/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index e82961ec..461e2a1b 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -7,6 +7,7 @@ Now you have to implement each handler. You need to inherit from WSF_SKELETON_HA ### is_chunking HTTP/1.1 supports streaming responses (and providing you have configured your server to use a proxy server in WSF_PROXY_USE_POLICY, this framework guarantees you have an HTTP/1.1 client to deal with). It is up to you whether or not you choose to make use of it. If so, then you have to serve the response one chunk at a time (but you could generate it all at once, and slice it up as you go). In this routine you just say whether or not you will be doing this. So the framework n=knows which other routines to call. +Currently we only support chunking for GET or HEAD routines. This might change in the future, so if you intend to return True, you should call req.is_get_head_request_method. ### includes_response_entity @@ -59,6 +60,33 @@ You need to implement this. If you do not have information about when a resource This routine when a PUT request is made to a resource that does not exist. See [PUT](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6) in the HTTP/1.1 specification for why you might want to return zero. +## allow_post_to_missing_resource + +POST requests are normally made to an existing entity. However it is possible to create new resources using a POST, if the server allows it. This is where you make that decision. + +If you return True, and the resource is created, a 201 Created response will be returned. + +## content_length + +If you are not streaming the result, the the HTTP protocol requires that the length of the entity is known. You need to implement this routine to provide that information. + +## finished + +If you are streaming the response, then you need to tell the framework when the last chunk has been sent. +To implement this routine, you will probably need to call req.set_execution_variable (some-name, True) in ensure_content_avaiable and generate_next_chunk, and call attached {BOOLEAN} req.execution_variable (some-name) in this routine. + +## description + +This is for the automatically generated documentation that the framework will generate in response to a request that you have not mapped into an handler. + +## delete + +This routine is for carrying out a DELETE request to a resource. If it is valid to delete the named resource, then you should either go ahead and do it, or queue a deletion request somewhere (if you do that then you will probably need to call req.set_execution_variable (some-name-or-other, True). Otherwise you should call req.error_handler.add_custom_error to explain why the DELETE could not proceed (you should also do this if the attempt to delete the resource fails). +Of course, if you have not mapped any DELETE requests to the URI space of this handler, then you can just do nothing. + +## delete_queued + +If in the delete routine, you elected to queue the request, then you need to return True here. You will probably need to check the execution variable you set in the delete routine. ## Implementing the policies * [WSF_OPTIONS_POLICY](./WSF_OPTIONS_POLICY) From 7e4f51a7ceb4e0a774bfc2e0a94871ba74dea8bf Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 09:58:42 -0700 Subject: [PATCH 163/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 461e2a1b..cd09a20d 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -60,33 +60,34 @@ You need to implement this. If you do not have information about when a resource This routine when a PUT request is made to a resource that does not exist. See [PUT](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6) in the HTTP/1.1 specification for why you might want to return zero. -## allow_post_to_missing_resource +### allow_post_to_missing_resource POST requests are normally made to an existing entity. However it is possible to create new resources using a POST, if the server allows it. This is where you make that decision. If you return True, and the resource is created, a 201 Created response will be returned. -## content_length +### content_length If you are not streaming the result, the the HTTP protocol requires that the length of the entity is known. You need to implement this routine to provide that information. -## finished +### finished If you are streaming the response, then you need to tell the framework when the last chunk has been sent. To implement this routine, you will probably need to call req.set_execution_variable (some-name, True) in ensure_content_avaiable and generate_next_chunk, and call attached {BOOLEAN} req.execution_variable (some-name) in this routine. -## description +### description This is for the automatically generated documentation that the framework will generate in response to a request that you have not mapped into an handler. -## delete +### delete This routine is for carrying out a DELETE request to a resource. If it is valid to delete the named resource, then you should either go ahead and do it, or queue a deletion request somewhere (if you do that then you will probably need to call req.set_execution_variable (some-name-or-other, True). Otherwise you should call req.error_handler.add_custom_error to explain why the DELETE could not proceed (you should also do this if the attempt to delete the resource fails). Of course, if you have not mapped any DELETE requests to the URI space of this handler, then you can just do nothing. -## delete_queued +### delete_queued If in the delete routine, you elected to queue the request, then you need to return True here. You will probably need to check the execution variable you set in the delete routine. + ## Implementing the policies * [WSF_OPTIONS_POLICY](./WSF_OPTIONS_POLICY) From 2415a57ab08d9eb3c2d85e10d233dcbc7310a73c Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 7 Aug 2013 23:30:49 -0700 Subject: [PATCH 164/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index cd09a20d..ce845fd8 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -88,6 +88,10 @@ Of course, if you have not mapped any DELETE requests to the URI space of this h If in the delete routine, you elected to queue the request, then you need to return True here. You will probably need to check the execution variable you set in the delete routine. +### deleted + +If delete_queued returns False, then deleted needs to indicate whether or not the delete succeeded. A default implementation is provided that should be satisfactory. + ## Implementing the policies * [WSF_OPTIONS_POLICY](./WSF_OPTIONS_POLICY) From bc976c37b14bd2398e094151660c6dcf9f87c3b4 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Thu, 8 Aug 2013 00:26:56 -0700 Subject: [PATCH 165/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index ce845fd8..be116a37 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -88,9 +88,37 @@ Of course, if you have not mapped any DELETE requests to the URI space of this h If in the delete routine, you elected to queue the request, then you need to return True here. You will probably need to check the execution variable you set in the delete routine. -### deleted +### ensure_content_available -If delete_queued returns False, then deleted needs to indicate whether or not the delete succeeded. A default implementation is provided that should be satisfactory. +This routine is called for GET and DELETE (when a entity is provided in the response) processing. It's purpose is to make the text of the entity (body of the response) available for future routines (if is_chunking is true, then only the first chunk needs to be made available, although if you only serve, as opposed to generate, the result in chunks, then you will make the entire entity available here). This is necessary so that we can compute the length before we start to serve the response. You would normally save it in an execution variable on the request object (as ORDER_HANDLER does). Note that this usage of execution variables ensures your routines can successfully cope with simultaneous requests. If you encounter a problem generating the content, then add an error to req.error_handler. + +As well as the request object, we provide the results of content negotiation, so you can generate the entity in the agreed format. If you only support one format (i.e. all of mime_types_supported, charsets_supported, encodings_supported and languages_supported are one-element lists), then you are guaranteed that this is what you are being asked for, and so you can ignore them. + +### content + +When not streaming, this routine provides the entity to the framework (for GET or DELETE). Normally you would just access the execution variable that you set in ensure_content_available. Again, the results of content negotiation are made available, but you probably don't need them at this stage. If you only stream responses (for GET), and if you don't support DELETE, then you don't need to do anything here. + +### generate_next_chunk + +When streaming the response, this routine is called to enable you to generate chunks beyond the first, so that you can incrementally generate the response entity. If you generated the entire response entity in +ensure_content_available, then you do nothing here. Otherwise, you will generate the next chunk, and save it in the same execution variable that you use in ensure_content_available (or add an error to req.error_handler). If you don't support streaming, then you don't need to do anything here. + +### next_chunk + +When streaming the response, the framework calls this routine to provides the contents of each generated chunk. If you generated the entire response entity in ensure_content_available, then you need to slice it in this routine (you will have to keep track of where you are with execution variables). If instead you generate the response incrementally, then your task is much easier - you just access the execution variable saved in ensure_content_available/generate_next_chunk. +As in all these content-serving routines, we provide the results of content negotiation. This might be necessary, for instance, if you were compressing an incrementally generated response (it might be more convenient to do the compression here rather than in both ensure_content_available and generate_next_chunk). + +### read_entity + +This is called for PUT and POST processing, to read the entity provided in the request. A default implementation is provided. This assumes that no decoding (e.g. decompression or character set conversion) is necessary. And it saves it in the execution variable REQUEST_ENTITY. + +Currently the framework provides very little support for PUT and POST requests (so you may well need to redefine this routine). There are several reasons for this: + +1. I personally don't have much experience with PUT and POST. +1. It has taken a long time to develop this framework, and to some extent I was working in the dark (I couldn't check what I was doing until the entire framework was written - it wouldn't even compile before then). +1. The idea for the framework came from a code review process on servers I had written for the company that I work for. I had acquired a lot of knowledge of the HTTP protocol in the process, and some of it showed in the code that I had written. It was thought that it would be a good idea if this knowledge were encapsulated in Eiffel, so other developers would be able to write servers without such knowledge. So this framework has been developed in company time. However, at present, we are only using GET requests. + +Experience with converting the restbucksCRUD example to use the framework, shows that it is certainly possible to do POST and PUT processing with it. But enhancements are needed, especially in the area of decoding the request entity. ## Implementing the policies From e9013e548b56c1e64db7027187b3a8b8f93c862b Mon Sep 17 00:00:00 2001 From: colin-adams Date: Thu, 8 Aug 2013 00:56:14 -0700 Subject: [PATCH 166/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index be116a37..ab456856 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -120,6 +120,34 @@ Currently the framework provides very little support for PUT and POST requests ( Experience with converting the restbucksCRUD example to use the framework, shows that it is certainly possible to do POST and PUT processing with it. But enhancements are needed, especially in the area of decoding the request entity. +### is_entity_too_large + +If your application has limits on the size of entities that it can store, then you implement them here. + +### check_content_headers + +This is called after is_entity_too_large returns False. You are supposed to check the following request headers, and take any appropriate actions (such as setting an error, decompression the entity, or converting it to a different character set): + +* Content-Encoding +* Content-Language +* Content-MD5 +* Content-Range +* Content-Type + +At the moment, your duty is to set the execution variable CONTENT_CHECK_CODE to zero, or an HTTP error status code. A future enhancement of the framework might be to provide more support for this. + +### content_check_code + +This simply accesses the execution variable CONTENT_CHECK_CODE set in check_content_headers. if you want to use some other mechanism, then you can redefine this routine. + +### create_resource + +This routine is called when a PUT request is made with a URI that refers to a resource that does not exist (PUT is normally used for updating an existing resource), and you have already decided to allow this. +In this routine you have the responsibilities of: + +1. Creating the resource using the entity in REQUEST_ENTITY (or some decoded version that you have stored elsewhere). +1. Writing the entire response yourself (as I said before, support for PUT and POST processing is poor at present), including setting the status code of 201 Created or 303 See Other or 500 Internal server error). + ## Implementing the policies * [WSF_OPTIONS_POLICY](./WSF_OPTIONS_POLICY) From 2dac1ff6c9f187a1d21ef8840a127b3937afdd9d Mon Sep 17 00:00:00 2001 From: colin-adams Date: Thu, 8 Aug 2013 01:25:29 -0700 Subject: [PATCH 167/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index ab456856..922ed6cf 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -148,6 +148,30 @@ In this routine you have the responsibilities of: 1. Creating the resource using the entity in REQUEST_ENTITY (or some decoded version that you have stored elsewhere). 1. Writing the entire response yourself (as I said before, support for PUT and POST processing is poor at present), including setting the status code of 201 Created or 303 See Other or 500 Internal server error). +### append_resource + +This routine is called for POST requests on an existing resource (normal usage). + +In this routine you have the responsibilities of: + +1. Storing the entity from REQUEST_ENTITY (or some decoded version that you have stored elsewhere), or whatever other action is appropriate for the semantics of POST requests to this URI. +1. Writing the entire response yourself (as I said before, support for PUT and POST processing is poor at present), including setting the status code of 200 OK, 204 No Content, 303 See Other or 500 Internal server error). + +### check_conflict + +This is called for a normal (updating) PUT request. You have to check to see if the current state of the resource makes updating impossible. If so, then you need to write the entire response with a status code of 409 Conflict, and set the execution variable CONFLICT_CHECK_CODE to 409. +Otherwise you just set the execution variable CONFLICT_CHECK_CODE to 0. + +See [the HTTP/1.1 specification](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.10) for when you are allowed to use the 409 response, and what to write in the response entity. If this is not appropriate then a 500 Internal server error would be more appropriate (and set CONFLICT_CHECK_CODE to 500 - the framework only tests for non-zero). + +### conflict_check_code + +This is implemented to check CONFLICT_CHECK_CODE from the previous routine. If you choose to use a different mechanism, then you need to redefine this. + +### check_request + +This is called for PUT and POST requests. You need to check that the request entity (available in the execution variable REQUEST_ENTITY) is valid for the semantics of the request URI. You should set the execution variable REQUEST_CHECK_CODE to 0 if it is OK. If not, set it to 400 and write the full response, including a status code of 400 Bad Request. + ## Implementing the policies * [WSF_OPTIONS_POLICY](./WSF_OPTIONS_POLICY) From 9c8a034a041d6277e9570174ed4eb1f843bfce0a Mon Sep 17 00:00:00 2001 From: colin-adams Date: Thu, 8 Aug 2013 01:32:31 -0700 Subject: [PATCH 168/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 922ed6cf..252d6bdf 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -172,6 +172,14 @@ This is implemented to check CONFLICT_CHECK_CODE from the previous routine. If y This is called for PUT and POST requests. You need to check that the request entity (available in the execution variable REQUEST_ENTITY) is valid for the semantics of the request URI. You should set the execution variable REQUEST_CHECK_CODE to 0 if it is OK. If not, set it to 400 and write the full response, including a status code of 400 Bad Request. +### request_check_code + +This routine just checks REQUEST_CHECK_CODE. if you choose to use a different mechanism, then redefine it. + +### update_resource + +This routine is called for a normal (updating) PUT request. You have to update the state of the resource using the entity saved in the execution environment variable REQUEST_ENTITY (or more likely elsewhere - see what ORDER_HANDLER does). Then write the entire response including a status code of 204 No Content or 500 Internal server error. + ## Implementing the policies * [WSF_OPTIONS_POLICY](./WSF_OPTIONS_POLICY) From bbbf958d7d10d73901b838c6cd9ed620ac314f2d Mon Sep 17 00:00:00 2001 From: colin-adams Date: Thu, 8 Aug 2013 02:41:27 -0700 Subject: [PATCH 169/178] Updated Using the policy driven framework (markdown) --- Using-the-policy-driven-framework.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Using-the-policy-driven-framework.md b/Using-the-policy-driven-framework.md index 2999ec9a..af97acde 100644 --- a/Using-the-policy-driven-framework.md +++ b/Using-the-policy-driven-framework.md @@ -1,5 +1,7 @@ # Using the policy driven framework +**This describes a new facility that is not yet in the EWF release** + ## Introduction The aim of the policy-driven framework is to allow authors of web-servers to concentrate on the business logic (e.g., in the case of a GET request, generating the content), without having to worry about the details of the HTTP protocol (such as headers and response codes). However, there are so many possibilities in the HTTP protocol, that it is impossible to correctly guess what to do in all cases. Therefore the author has to supply policy decisions to the framework, in areas such as caching decisions. These are implemented as a set of deferred classes for which the author needs to provide effective implementations. From fe971d07ec6760bce9c7e5214228c39c1c67b05b Mon Sep 17 00:00:00 2001 From: colin-adams Date: Sun, 11 Aug 2013 23:55:50 -0700 Subject: [PATCH 170/178] Updated Using the policy driven framework (markdown) --- Using-the-policy-driven-framework.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Using-the-policy-driven-framework.md b/Using-the-policy-driven-framework.md index af97acde..bf85c9ef 100644 --- a/Using-the-policy-driven-framework.md +++ b/Using-the-policy-driven-framework.md @@ -6,7 +6,7 @@ The aim of the policy-driven framework is to allow authors of web-servers to concentrate on the business logic (e.g., in the case of a GET request, generating the content), without having to worry about the details of the HTTP protocol (such as headers and response codes). However, there are so many possibilities in the HTTP protocol, that it is impossible to correctly guess what to do in all cases. Therefore the author has to supply policy decisions to the framework, in areas such as caching decisions. These are implemented as a set of deferred classes for which the author needs to provide effective implementations. -We aim to provide unconditional compliance [See HTTP/1.1 specification](http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html#sec1) for you. +We aim to provide unconditional compliance [See HTTP/1.1 specification](http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html#sec1) for you. Note that byte-ranges are not yet supported. ## Mapping the URI space From 35224b1b171bfe06a43441feb5dfa9ae8b6d062f Mon Sep 17 00:00:00 2001 From: colin-adams Date: Mon, 12 Aug 2013 01:45:58 -0700 Subject: [PATCH 171/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 252d6bdf..933c3a09 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -8,6 +8,7 @@ Now you have to implement each handler. You need to inherit from WSF_SKELETON_HA HTTP/1.1 supports streaming responses (and providing you have configured your server to use a proxy server in WSF_PROXY_USE_POLICY, this framework guarantees you have an HTTP/1.1 client to deal with). It is up to you whether or not you choose to make use of it. If so, then you have to serve the response one chunk at a time (but you could generate it all at once, and slice it up as you go). In this routine you just say whether or not you will be doing this. So the framework n=knows which other routines to call. Currently we only support chunking for GET or HEAD routines. This might change in the future, so if you intend to return True, you should call req.is_get_head_request_method. +Note that currently this framework does not support writing a trailer. ### includes_response_entity @@ -47,10 +48,14 @@ If the response may vary in other ways not predictable from the request headers, An **ETag** header is a kind of message digest. Clients can use etags to avoid re-fetching responses for unchanged resources, or to avoid updating a resource that may have changed since the client last updated it. You must implement this routine to test for matches **if and only if** you return non-Void responses for the etag routine. +Note that if you support multiple representations through content negotiation, then etags are dependent upon +the selected variant. Therefore you will need to have the response entity available for this routine. This can be done in check_resource_exists. ### etag You are strongly encouraged to return non-Void for this routine. See [Validation Model](http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3) for more details. +Note that if you support multiple representations through content negotiation, then etags are dependent upon +the selected variant. Therefore you will need to have the response entity available for this routine. This can be done in check_resource_exists. ### modified_since @@ -94,6 +99,9 @@ This routine is called for GET and DELETE (when a entity is provided in the resp As well as the request object, we provide the results of content negotiation, so you can generate the entity in the agreed format. If you only support one format (i.e. all of mime_types_supported, charsets_supported, encodings_supported and languages_supported are one-element lists), then you are guaranteed that this is what you are being asked for, and so you can ignore them. +Note that if you support multiple representations through content negotiation, then etags are dependent upon +the selected variant. Therefore you will need to have the response entity available for this routine. In such cases, this will have to be done in check_resource_exists, rather than here, as this routine is called later on. + ### content When not streaming, this routine provides the entity to the framework (for GET or DELETE). Normally you would just access the execution variable that you set in ensure_content_available. Again, the results of content negotiation are made available, but you probably don't need them at this stage. If you only stream responses (for GET), and if you don't support DELETE, then you don't need to do anything here. From bf5bae803d8c8c30c772e4bf8e8fa3daabaa2398 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Mon, 12 Aug 2013 01:49:11 -0700 Subject: [PATCH 172/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 933c3a09..99c557c1 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -4,6 +4,12 @@ Now you have to implement each handler. You need to inherit from WSF_SKELETON_HA ## Implementing the routines declared directly in WSF_SKELETON_HANDLER +### check_resource_exists + +Here you check for the existence of the resource named by the request URI. If it does, then you need to call set_resource_exists on the helper argument. +Note that if you support multiple representations through content negotiation, then etags are dependent upon +the selected variant. If you support etags, then you will need to make the response entity available at this point, rather than in ensure_content_available. + ### is_chunking HTTP/1.1 supports streaming responses (and providing you have configured your server to use a proxy server in WSF_PROXY_USE_POLICY, this framework guarantees you have an HTTP/1.1 client to deal with). It is up to you whether or not you choose to make use of it. If so, then you have to serve the response one chunk at a time (but you could generate it all at once, and slice it up as you go). In this routine you just say whether or not you will be doing this. So the framework n=knows which other routines to call. From 9c8bc59224de4318558a92d66f54b47631459654 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Tue, 13 Aug 2013 00:54:45 -0700 Subject: [PATCH 173/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 99c557c1..6af6d39f 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -2,6 +2,22 @@ Now you have to implement each handler. You need to inherit from WSF_SKELETON_HANDLER (as ORDER_HANDLER does). This involves implementing a lot of deferred routines. There are other routines for which default implementations are provided, which you might want to override. This applies to both routines defined in this class, and those declared in the three policy classes from which it inherits. +## Communicating between routines + +Depending upon the connector (Nino, CGI, FastCGI etc.) that you are using, your handler may be invoked concurrently for multiple requests. Therefore it is unsafe to save state in normal attributes. WSF_REQUEST has a pair of getter/setter routines, execution_variable/set_execution_variable, which you can use for this purpose. +Internally, the framework uses the following execution variable names, so you must avoid them: + +1. REQUEST_ENTITY +1. NEGOTIATED_LANGUAGE +1. NEGOTIATED_CHARSET +1. NEGOTIATED_MEDIA_TYPE +1. NEGOTIATED_ENCODING +1. NEGOTIATED_HTTP_HEADER + +The first one makes the request entity from a PULL or POST request available to your routines. + +The next four make the results of content negotiation available to your routines. The last one makes an HTTP_HEADER available to your routines. You should use this rather than create your own, as it may contain a **Vary** header as a by-product of content negotiation. + ## Implementing the routines declared directly in WSF_SKELETON_HANDLER ### check_resource_exists From 123fc8252e62bf6edcbf3921be2d0e828c8dfa8c Mon Sep 17 00:00:00 2001 From: colin-adams Date: Tue, 13 Aug 2013 08:24:05 -0700 Subject: [PATCH 174/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 6af6d39f..6bc01145 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -18,6 +18,8 @@ The first one makes the request entity from a PULL or POST request available to The next four make the results of content negotiation available to your routines. The last one makes an HTTP_HEADER available to your routines. You should use this rather than create your own, as it may contain a **Vary** header as a by-product of content negotiation. +All six names are defined as constants in WSF_SKELETON_HANDLER, to make it easier for you to refer to them. + ## Implementing the routines declared directly in WSF_SKELETON_HANDLER ### check_resource_exists From 5e62d82e9ce92acc15993d26b96129115c1794b1 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 14 Aug 2013 02:22:22 -0700 Subject: [PATCH 175/178] Updated Wsf previous policy (markdown) --- Wsf-previous-policy.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Wsf-previous-policy.md b/Wsf-previous-policy.md index 37c965c5..1ba251d0 100644 --- a/Wsf-previous-policy.md +++ b/Wsf-previous-policy.md @@ -1,20 +1,19 @@ -# Implementing WSF_PREVIOUS_POLICY +# WSF_PREVIOUS_POLICY -This class provides routines which enable the programmer to encode knowledge about resources that have moved (either temporarily, or permanently), or have been permanently removed. There are four routines, but only one is actually deferred. +This class deals with resources that have moved or gone. The default assumes no such resources. It exists as a separate class, rather than have the routines directly in WSF_SKELETON_HANDLER, as sub-classing it may be convenient for an organisation. ## resource_previously_existed -By default, this routine says that currently doesn't exist, never has existed. You need to redefine this routine to return True for any URIs that you want to indicate used to exist, and either no longer do so, or have moved to another location. +Redefining this routine is always necessary if you want to deal with any previous resources. ## resource_moved_permanently -If you have indicated that a resource previously existed, then it may have moved permanently, temporarily, or just ceased to exist. In the first case, you need to redefine this routine to return True for such a resource. +Redefine this routine for any resources that have permanently changed location. The framework will generate a 301 Moved Permanently response, and the user agent will automatically redirect the request to (one of) the new location(s) you provide. The user agent will use the new URI for future requests. + ## resource_moved_temporarily -If you have indicated that a resource previously existed, then it may have moved permanently, temporarily, or just ceased to exist. In the second case, you need to redefine this routine to return True for such a resource. +This is for resource that have only been moved for a short period. The framework will generate a 302 Found response. The only substantial difference between this and resource_moved_permanently, is that the agent will use the old URI for future requests. ## previous_location -You need to implement this routine. It should provide the locations where a resource has moved to. There must be at least one such location. If more than one is provided, then the first one is considered primary. - -If the preconditions for this routine are never met (as is the case by default), then just return an empty list. \ No newline at end of file +When you redefine resource_moved_permanently or resource_moved_temporarily, the framework will generate a Location header for the new URI, and a hypertext document to the new URI(s). You **must** redefine this routine to provide those locations (the first one you provide will be in the location header). \ No newline at end of file From bcdfcdd468bd948453b1c83369edf46be477de90 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 14 Aug 2013 02:23:07 -0700 Subject: [PATCH 176/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 6bc01145..37c43630 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -215,5 +215,5 @@ This routine is called for a normal (updating) PUT request. You have to update t ## Implementing the policies * [WSF_OPTIONS_POLICY](./WSF_OPTIONS_POLICY) -* [WSF_PREVIOUS_POLICY](./WSF_PREVIOUS_POLICY) +* [WSF_PREVIOUS_POLICY](./Wsf-previous-policy) * [WSF_CACHING_POLICY](./WSF_CACHING_POLICY) \ No newline at end of file From aff7948c65088d58eb208ddf91bffd04cb39d284 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 14 Aug 2013 02:23:53 -0700 Subject: [PATCH 177/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 37c43630..50770637 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -216,4 +216,4 @@ This routine is called for a normal (updating) PUT request. You have to update t * [WSF_OPTIONS_POLICY](./WSF_OPTIONS_POLICY) * [WSF_PREVIOUS_POLICY](./Wsf-previous-policy) -* [WSF_CACHING_POLICY](./WSF_CACHING_POLICY) \ No newline at end of file +* [WSF_CACHING_POLICY](./Wsf-caching-policy) \ No newline at end of file From b2d9fe1a4b7e9d8ff60b9a2ea58a649de17857c8 Mon Sep 17 00:00:00 2001 From: colin-adams Date: Wed, 14 Aug 2013 02:47:12 -0700 Subject: [PATCH 178/178] Updated Writing the handlers (markdown) --- Writing-the-handlers.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Writing-the-handlers.md b/Writing-the-handlers.md index 50770637..87e68a2c 100644 --- a/Writing-the-handlers.md +++ b/Writing-the-handlers.md @@ -13,12 +13,16 @@ Internally, the framework uses the following execution variable names, so you mu 1. NEGOTIATED_MEDIA_TYPE 1. NEGOTIATED_ENCODING 1. NEGOTIATED_HTTP_HEADER +1. CONFLICT_CHECK_CODE +1. CONTENT_CHECK_CODE +1. REQUEST_CHECK_CODE The first one makes the request entity from a PULL or POST request available to your routines. -The next four make the results of content negotiation available to your routines. The last one makes an HTTP_HEADER available to your routines. You should use this rather than create your own, as it may contain a **Vary** header as a by-product of content negotiation. +The next four make the results of content negotiation available to your routines. The sixth one makes an HTTP_HEADER available to your routines. You should use this rather than create your own, as it may contain a **Vary** header as a by-product of content negotiation. +The last three are for reporting the result from check_conflict, check_content and check_request. -All six names are defined as constants in WSF_SKELETON_HANDLER, to make it easier for you to refer to them. +All names are defined as constants in WSF_SKELETON_HANDLER, to make it easier for you to refer to them. ## Implementing the routines declared directly in WSF_SKELETON_HANDLER