Compare commits

...

41 Commits

Author SHA1 Message Date
98c12b8fb9 Made HTTP_DATE more flexible and support UTC+0000, GMT+0000 and now also +0000.
Added comments.
2015-10-08 11:00:01 +02:00
5fee483fd9 Added FEED + FEED operator to merge two feeds.
Added FEED sorting routine.
Added FEED_ITEM.link: detachable FEED_LINK that represents the main feed link.
Comments.
2015-10-08 10:10:08 +02:00
f7a7afccd6 Fixed compilation of non void-safe feed.ecf 2015-10-05 22:58:58 +02:00
e2c70e6d70 Updated a few comments.
Renamed generator to follow *_FEED_GENERATOR naming.
Renamed feed entry as feed item.
Made FEED conforms to ITERABLE [FEED_ITEM] for convenience.
2015-09-16 10:02:09 +02:00
a5e150d1c0 Improved feed library with comments, bug fixes and code factorization. 2015-09-08 21:45:27 +02:00
39887c8bdb Added initial ATOM and RSS feed parser and generator.
(work in progress)
2015-09-07 19:22:50 +02:00
jvelilla
1f1e2abbda Removed support for SSLv3 2015-08-26 11:56:24 -03:00
1796d9631f Added target "all_stable_with_ssl" to check compilation with ssl enabled. 2015-08-26 13:38:50 +02:00
389975e409 Merge branch 'v1' 2015-08-24 16:13:01 +02:00
6c51590369 Updated installation location of openid and http_authorization in ISE package.
Added iron package file for ewsgi.
2015-08-24 16:12:25 +02:00
jvelilla
cc65bae644 Fixed typo: Aug instead of Aou. 2015-08-06 10:45:47 +02:00
jvelilla
c824f707cf Fixed typo: Aug instead of Aou. 2015-08-06 10:42:15 +02:00
47c5b798b3 Cosmetic true -> True 2015-08-04 13:24:03 +02:00
f0cba1d536 Fixing script_url' that wrongly used path_info' instead of `percent_encoded_path_info'.
(issue on script_url when path info contains unicode character).
2015-08-04 13:21:36 +02:00
ed891546bc Updated set_value for WSF_FORM_SELECTABLE_INPUT (for example a checkbox).
Call the feature set_checked_by_value iff the the current value exist in the
list of values, in other case set checked in Flase.
If we call set_checked_by_value without filter, previous checked values will be
set in False.
2015-08-04 13:21:07 +02:00
8651ff6e1e Fixing script_url' that wrongly used path_info' instead of `percent_encoded_path_info'.
(issue on script_url when path info contains unicode character).
2015-08-04 13:03:51 +02:00
629edea991 Merge remote-tracking branch 'javier/ewf_html_form' into v1 2015-08-04 13:00:08 +02:00
jvelilla
1e10ce8518 Updated set_value for WSF_FORM_SELECTABLE_INPUT (for example a checkbox).
Call the feature set_checked_by_value iff the the current value exist in the
list of values, in other case set checked in Flase.
If we call set_checked_by_value without filter, previous checked values will be
set in False.
2015-07-31 11:55:23 -03:00
4f8f17ad48 Fixed various compilation issues.
Ensure the obsolete/v0 ecf has new UUID.
2015-07-03 20:02:13 +02:00
148518984e Added the possibility to provide the sendmail location in NOTIFICATION_SENDMAIL_MAILER.
Added NOTIFICATION_STORAGE_MAILER which allow to store the email in a storage (could be just output, file, database ...)
Added SMTP implementation, based on EiffelNet SMTP_PROTOCOL.
   note: it is possible to exclude this by setting ecf variable "smtp_notification_email_disabled" to "True"
   this way help to manage dependencies, since the Eiffel Net library would not be included neither.
Fixed Date header value computation.
2015-07-03 10:02:56 +02:00
33150e34d6 Reverted previous changed related to redefinition of set_status_code which was against existing assertions. 2015-07-02 15:11:33 +02:00
af60a5719e Updated eiffelstudio locations for EWF libraries. 2015-07-02 13:06:38 +02:00
31557cfc33 Fixed WGI_HTTPD_REQUEST_HANDLER.process_rescue
Fixed WGI_STANDALONE_OUTPUT_STREAM.is_available
Added WGI_STANDALONE_RESPONSE_STREAM.is_persistent_connection_supported
2015-07-02 10:50:41 +02:00
78c0cd5b0d Merge branch 'v1' of https://github.com/EiffelWebFramework/EWF into v1 2015-07-01 21:48:47 +02:00
412534d0be Fixed compilation of all*-safe.ecf files.
Corrected a few comments.
2015-07-01 21:43:54 +02:00
jvelilla
0f6aa8d7ae Merge branch 'jvelilla-ewf_v1_workbook' into v1 2015-06-30 09:58:40 -03:00
jvelilla
2c745c63d3 Updated workbook: generating response, handling cookies and headers documents. 2015-06-30 09:21:12 -03:00
jvelilla
efd80c1287 Updated workbook form document 2015-06-30 09:00:47 -03:00
jvelilla
01f649fd88 Updated: workbook headers document.
Removed: unnecessary files.
2015-06-30 08:57:00 -03:00
jvelilla
f23aeb6412 Updated Workbook basic documentation. 2015-06-30 08:42:29 -03:00
jvelilla
1a4596c79b Merge branch 'ewf_v1_workbook' of https://github.com/jvelilla/EWF into ewf_v1_workbook 2015-06-29 19:05:25 -03:00
jvelilla
b16e4aa570 Updated basic documentation 2015-06-29 19:03:54 -03:00
Javier Velilla
5255b15fa9 Update basics.md 2015-06-29 18:36:44 -03:00
jvelilla
57048373f4 Update basic document 2015-06-29 18:30:11 -03:00
Javier Velilla
9e06fb2ab8 Update basics.md 2015-06-29 16:24:09 -03:00
Javier Velilla
f2405e0ccd Update basics.md 2015-06-29 16:22:01 -03:00
Javier Velilla
6e3a7deb6e Update workbook.md 2015-06-29 16:20:19 -03:00
jvelilla
f254b599c0 Update basic document to the new EWF concurrent design 2015-06-29 16:17:43 -03:00
99a05b95ba Improved code related to cookie management (avoid duplicated cookie). 2015-06-22 22:06:16 +02:00
54dd43c38a Synchronized wsf-safe.ecf and wsf.ecf 2015-06-18 14:53:19 +02:00
d0836d49a4 Merge branch 'v1' 2015-06-10 09:49:28 +02:00
90 changed files with 2845 additions and 373 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,4 +1,4 @@
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/workbook/handling_request/form.md)
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/doc/workbook/handling_request/form.md)
## EWF basic service
@@ -14,133 +14,140 @@ Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/wor
<a name="structure"/>
## EWF service structure
The following code describes the basic structure of an EWF basic service that handles HTTP requests.
The following code describes the basic structure of an EWF basic service that handles HTTP requests. We will need to define a Service Launcher and a Request Execution implementation.
```eiffel
class
SERVICE_TEMPLATE
APPLICACTION
inherit
WSF_DEFAULT_SERVICE -- Todo explain this, and the concept of launchers and connectors ()
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
create
make_and_launch
make_and_launch
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
do
-- To read incoming HTTP request, we need to use `req'
-- May require talking to databases or other services.
-- To send a response we need to setup, the status code and
-- the response headers and the content we want to send out our client
end
end
```
When using the "nino" connector, by default the service listens on port 80, but often this port is already used by other applications, so it is recommended to use another port.
To define another port, redefine the feature `initialize' and set up a new port number using the service options (see below).
The class ```APPLICATION``` inherit from
```WSF_DEFAULT_SERVICE [G ->WSF_EXECUTION create make end]``` it will be responsible to launch the service and set optional options.
The class ```APPLICATION_EXECUTION``` is an implementation of ```WSF_EXECUTION``` interface, which is instantiated for each incoming request.
```eiffel
class
SERVICE_TEMPLATE
APPLICATION_EXECUTION
inherit
WSF_DEFAULT_SERVICE
redefine
WSF_EXECUTION
create
make
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
do
-- To read incoming HTTP request, we need to use `req'
-- May require talking to databases or other services.
-- To send a response we need to setup, the status code and
-- the response headers and the content we want to send out our client
end
end
```
When using the "nino" connector or the new "standalone" connector, by default the service listens on port 80, but often this port is already used by other applications, so it is recommended to use another port.
To define another port, redefine the feature `initialize' and set up a new port number using the service options (see below).
```eiffel
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
redefine
initialize
end
create
make_and_launch
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
-- on port 9090
do
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incoming request.
do
-- To read incoming HTTP requires, we need to use `req'
-- May require talking to databases or other services.
-- To send a response we need to setup, the status code and
-- the response headers and the content we want to send out client
end
end
```
The **WSF_REQUEST** gives access to the incoming data; the class provides features to get information such as request method, form data, query parameters, uploaded files, HTTP request headers, and hostname of the client among others.
The **WSF_RESPONSE** provides features to define the response with information such as HTTP status codes (10x,20x, 30x, 40x, and 50x), response headers (Content-Type, Content-Length, etc.) and obviously the body of the message itself.
**SERVICE_TEMPLATE** is the root class of our example, it launches the application, using the corresponding connector, Which connector? this depends how you want to run it cgi, fcgi or nino. For development is recommended to use Nino, a standalone web server written in Eiffel, and run the execution within the EiffelStudio debugger. For production fcgi (or cgi) using Apache or another popular web server.
**APPLICATION** is the root class of our example, it launches the application, using the corresponding connector, Which connector? this depends how you want to run it cgi, fcgi,nino or standalone. For development is recommended to use a standalone web server written in Eiffel, and run the execution within the EiffelStudio debugger. For production fcgi (or cgi) using Apache or another popular web server.
The **SERVICE_TEMPLATE** class inherits from _WSF_DEFAULT_SERVICE_ class, and this one also inherits from other interfaces. Lets describe them in a few words.
![Launcher Hierarchy](/doc/workbook/basics/Launcher Hierarchy.png "Launcher Hierarchy")
![Service Template Hierarchy](/workbook/SERVICE_TEMPLATE.png "Service Template")
**WS_LAUNCHABLE_SERVICE** inherit from **WS_SERVICE** class, which is a marker interface in EWF. And also provides a way to launch our application using different kind of connectors. The class **WSF_DEFAULT_SERVICE_I**, inherit from **WS_LAUNCHABLE_SERVICE** and has a formal generic that should conform to **WSF_SERVICE_LAUNCHER [WSF_EXECUTION]**. Below a [BON diagram] (http://www.bon-method.com/index_normal.htm) showing one of the possible options.
**WS_LAUNCHABLE_SERVICE** inherit from **WS_SERVICE** class, which is the low level entry point in EWF, handling each incoming request with a single procedure ```execute (req: WSF_REQUEST; res: WSF_RESPONSE) ...```. And also provides a way to launch our application using different kind of connectors. Below a [BON diagram] (http://www.bon-method.com/index_normal.htm) showing the different kind of connectors.
![Standalone Launcher](/doc/workbook/basics/WSF_SERVICE_LAUNCHER_STANDALONE.png "Standalone Hierarchy")
Other connectors:
![Launcher Hierarchy](/app/doc/WSF_SERVICE_LAUNCHER.png "Launcher")
**WSF_STANDALONE_SERVICE_LAUNCHER**
**WSF_CGI_SERVICE_LAUNCHER**
**WSF_NINO_SERVICE_LAUNCHER**
**WSF_LIBFCGI_SERVICE_LAUNCHER**
A basic EWF service inherits from **WSF_DEFAULT_SERVICE** (for other options see [?]).
And then you only need to implement the **execute** feature, get data from the request *req* and write the response in *res*.
A basic EWF service inherits from **WSF_DEFAULT_SERVICE**, which has a formal generic that should conform to **WSF_EXECUTION** class with a `make' creation procedure, in our case the class **APPLICATION_EXECUTION**.
The **APPLICATION_EXECUTION** class inherits from **WSF_EXECUTION** interface, which is instantiated for each incoming request. **WSF_EXECUTION** inherit from **WGI_EXECUTION** which is the low level entry point in EWF, handling each incoming request with a single procedure ```execute (req: WSF_REQUEST; res: WSF_RESPONSE) ...```.
In the **APPLICATION_EXECUTION** class class you will need to implement implement the **execute** feature, get data from the request *req* and write the response in *res*.
![Execution Hierarchy](/doc/workbook/basics/APPLICATION_EXECUTION.png "Application Execution ")
The WSF_EXECUTION instance, in this case ```APPLICATION_EXECUTION``` is created per request, with two main attributes request: ```WSF_REQUEST``` and response: ```WSF_RESPONSE```.
<a name="text"/>
## A simple Service to Generate Plain Text.
Before to continue, it is recommended to review the getting started guided.
Before to continue, it is recommended to review the getting started guided. In the example we will only shows the implementation of the WSF_EXECUTION interface.
```eiffel
class
APPLICATION
APPLICATION_EXECUTION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
WSF_EXECUTION
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
make
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
execute
-- Execute the incomming request
do
-- To send a response we need to setup, the status code and
-- the response headers.
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>)
res.put_string ("Hello World")
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>)
response.put_string ("Hello World")
end
end
```
<a name="source_1"></a>
##### Source code
The source code is available on Github. You can get it by running the command:
```git clone https://github.com/EiffelWebFramework/ewf_examples.git```
```git clone https://github.com/EiffelWebFramework/ewf.git```
The example of simple service that generate plain text response is located in the directory $PATH/ewf_examples/workbook/basics/simple, where $PATH is where you run ```git clone``` . Just double click on the simple.ecf file and select the simple_nino target or if you prefer the command line, run the command:
The example of simple service that generate plain text response is located in the directory $PATH/ewd/doc/workbook/basics/simple, where $PATH is where you run ```git clone``` . Just double click on the simple.ecf file and select the simple_nino target or if you prefer the command line, run the command:
```estudio -config simple.ecf -target simple_nino```
@@ -153,37 +160,25 @@ To generate HTML, it's needed
```eiffel
class
APPLICATION
APPLICATION_EXECUTION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
WSF_EXECUTION
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
make
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
execute
-- Execute the incomming request
do
-- To send a response we need to setup, the status code and
-- the response headers.
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
res.put_string (web_page)
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
response.put_string (web_page)
end
web_page: STRING = "[
<!DOCTYPE html>
<html>
@@ -201,11 +196,11 @@ end
##### Source code
The source code is available on Github. You can get it by running the command:
```git clone https://github.com/EiffelWebFramework/ewf_examples.git```
```git clone https://github.com/EiffelWebFramework/ewf.git```
The example of the service that generates HTML is located in the directory $PATH/ewf_examples/workbook/basics/simple_html, where $PATH is where you run ```git clone``` . Just double click on the simple_html.ecf file and select the simple_html_nino target or if you prefer the command line, run the command:
The example of the service that generates HTML is located in the directory $PATH/ewf/doc/workbook/basics/simple_html, where $PATH is where you run ```git clone``` . Just double click on the simple_html.ecf file and select the simple_html_nino target or if you prefer the command line, run the command:
```estudio -config simple_html.ecf -target simple_html_nino```
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/workbook/handling_request/form.md)
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/doc/workbook/handling_request/form.md)

View File

@@ -22,5 +22,4 @@ feature -- Basic operations
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>)
response.put_string ("Hello World")
end
end

View File

@@ -37,6 +37,14 @@
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="simple" location=".\" recursive="true"/>
</target>
<target name="simple_standalone" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_standalone" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\standalone-safe.ecf"/>
<cluster name="simple" location=".\" recursive="true"/>
</target>
<target name="simple" extends="simple_nino">
</target>
</system>

View File

@@ -1,5 +1,5 @@
Nav: [Workbook](../workbook.md) | [Handling Requests: Header Fields](/workbook/handling_request/headers.md) | [Handling Cookies](/workbook/handling_cookies/handling_cookies.md)
Nav: [Workbook](../workbook.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md) | [Handling Cookies](/doc/workbook/handling_cookies/handling_cookies.md)
## EWF Generating Response
@@ -164,24 +164,13 @@ Note: use ```res.set_status_code({HTTP_STATUS_CODE}.bad_request)``` rather than
Basic Service that builds a simple web page to show the most common status codes
```eiffel
class
APPLICATION
APPLICATION_EXECUTION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
WSF_EXECUTION
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
make
feature -- Basic operations
@@ -321,24 +310,13 @@ note
revision : "$Revision$"
class
APPLICATION
APPLICATION_EXECUTION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
WSF_EXECUTION
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
make
feature -- Basic operations
@@ -1018,4 +996,4 @@ There are four categories for response header fields:
| [Handling Requests: Header Fields](/workbook/handling_request/headers.md) | [Handling Cookies](/workbook/handling_cookies/handling_cookies.md)
Nav: [Workbook](../workbook.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md) | [Handling Cookies](/doc/workbook/handling_cookies/handling_cookies.md)

View File

@@ -1,4 +1,4 @@
Nav: [Workbook](../workbook.md) | [Generating Responses](/workbook/generating_response/generating_response.md)
Nav: [Workbook](../workbook.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md)
# Handling Cookies
@@ -146,25 +146,13 @@ note
revision : "$Revision$"
class
APPLICATION
APPLICATION_EXECUTION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
WSF_EXECUTION
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
set_service_option ("verbose",True)
end
make
feature -- Basic operations
@@ -297,4 +285,4 @@ end
```
Nav: [Workbook](../workbook.md) | [Generating Responses](/workbook/generating_response/generating_response.md)
Nav: [Workbook](../workbook.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md)

View File

@@ -1,4 +1,4 @@
Nav: [Workbook](../workbook.md) | [Basic Concepts] (/workbook/basics/basics.md) | [Handling Requests: Header Fields](/workbook/handling_request/headers.md)
Nav: [Workbook](../workbook.md) | [Basic Concepts] (/doc/workbook/basics/basics.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md)
#Handling Requests: Form/Query Data
@@ -285,25 +285,23 @@ and a simple message.
```
The source code is available on Github. You can get it by running the command:
```git clone https://github.com/EiffelWebFramework/ewf_examples.git```
```git clone https://github.com/EiffelWebFramework/ewf.git```
The example is located in the directory $PATH/ewf_examples/workbook/upload_file where $PATH is where you run git clone.
The example is located in the directory $PATH/ewf/doc/workbook/upload_file where $PATH is where you run git clone.
<a name=examples>
## Examples
The source code is available on Github. You can get it by running the command:
```git clone https://github.com/EiffelWebFramework/ewf_examples.git```
```git clone https://github.com/EiffelWebFramework/ewf.git```
The GET example is located in the directory $PATH/ewf_examples/workbook/form/get, and the post example is located in the directory $PATH/ewf_examples/workbook/form/post where $PATH is where you run git clone . To run open it using Eiffel Studio or just run theg following command
The GET example is located in the directory $PATH/ewf/doc/workbook/form/get, and the post example is located in the directory $PATH/ewf_examples/workbook/form/post where $PATH is where you run git clone . To run open it using Eiffel Studio or just run theg following command
```estudio -config <ecf_name>.ecf -target <target_name>```
>Note: replace <ecf_name> and<target_name> with the corresponding values.
Nav: [Workbook](../workbook.md) | [Basic Concepts] (/workbook/basics/basics.md) | [Handling Requests: Header Fields](/workbook/handling_request/headers.md)
Nav: [Workbook](../workbook.md) | [Basic Concepts] (/doc/workbook/basics/basics.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md)

View File

@@ -1,4 +1,4 @@
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/workbook/handling_request/form.md) | [Generating Responses](/workbook/generating_response/generating_response.md)
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/doc/workbook/handling_request/form.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md)
#Handling Requests: Headers
@@ -165,35 +165,26 @@ included in the Referer header when the browser requests Web page B.
* [User-Agent](https://httpwg.github.io/specs/rfc7231.html#header.user-agent)
- The "User-Agent" header field contains information about the user agent of the request, which is often used by servers to help identify the scope of reported interoperability problems, to work around or tailor responses to avoid particular user agent limitations, and for analytics regarding browser or operating system use or device.
**Note**: the example shows the **WSF_EXECUTION** implementation, that will be used by the service launcher.
<a name="example"></a>
#### Building a Table of All Request Headers
The following [EWF service](./headers/header_fields/application.e) code simply uses an ```html_template``` to fill a table (names and values) with all the headers fields it receives.
The following [EWF service](/doc/workbook/handling_request/headers/header_fields/application.e) code simply uses an ```html_template``` to fill a table (names and values) with all the headers fields it receives.
The service accomplishes this task by calling ```req.meta_variables``` feature to get an ```ITERABLE [WSF_STRING]```, an structure that can be iterated over using ```across...loop...end```, then it checks if the name has the prefix ```HTTP_``` and if it is true, put the header name and value in a row. (the name in the left cell, the value in the right cell).
The service also writes three components of the main request line (method, URI, and protocol), and also the raw header.
```eiffel
class
APPLICATION
APPLICATION_EXECUTION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
WSF_EXECUTION
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
set_service_option ("verbose", true)
end
make
feature -- Basic operations
@@ -293,32 +284,21 @@ To be completed.
#### Detecting Browser Types
The User-Agent header identifies the specific browser/client that is sending the request. The following code shows a [EWF service](./headers/browser_name/application.e) that sends browser-specific responses.
The User-Agent header identifies the specific browser/client that is sending the request. The following code shows a [EWF service](/doc/workbook/handling_request/headers/browser_name/application.e) that sends browser-specific responses.
The examples uses the ideas based on the [Browser detection using the user agent](https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent) article.
Basically the code check if the header user_agent exist and then call the ```browser_name (a_user_agent: READABLE_STRING_8): READABLE_STRING_32```
feature to retrieve the current browser name or Unknown in other case.
```eiffel
class
APPLICATION
APPLICATION_EXECUTION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
WSF_EXECUTION
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
set_service_option ("verbose", true)
end
make
feature -- Basic operations
@@ -329,8 +309,8 @@ feature -- Basic operations
l_page_response: STRING
l_rows: STRING
do
create l_page_response.make_from_string (html_template)
if req.path_info.same_string ("/") then
create l_page_response.make_from_string (html_template)
if req.path_info.same_string ("/") then
-- retrieve the user-agent
if attached req.http_user_agent as l_user_agent then
@@ -404,7 +384,7 @@ end
```
Let see some results, we will show the html returned
Internet Explorer
**Internet Explorer**
---
```
<h1>EWF service example: Showing Browser Dectection Using User-Agent</h1></br>
@@ -414,7 +394,7 @@ Internet Explorer
<h2> Enjoy using Internet Explorer </h2>
```
Chrome
**Chrome**
---
```
<h1>EWF service example: Showing Browser Dectection Using User-Agent</h1></br>
@@ -448,10 +428,11 @@ As an exercise, try to write a similar service to retrieve the OS family using t
* [SERVER_PROTOCOL](https://tools.ietf.org/html/rfc3875#section-4.1.15)
* [SERVER_SOFTWARE](https://tools.ietf.org/html/rfc3875#section-4.1.16)
An [EWF service](./headers/cgi_variables/application.e) that shows the CGI variables, creates a table showing the values of all the CGI variables.
**Example**
An [EWF service](/doc/workbook/handling_request/headers/cgi_variables/application.e) that shows the CGI variables, creates a table showing the values of all the CGI variables.
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/workbook/handling_request/form.md) | [Generating Responses](/workbook/generating_response/generating_response.md)
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/doc/workbook/handling_request/form.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md)

View File

@@ -19,20 +19,20 @@ Before reading (or walking throught) the workbook, to get a quick overview of EW
<a name="introduction"></a>
## Introduction
[Basic Concepts] (/workbook/basics/basics.md).
[Basic Concepts] (/doc/workbook/basics/basics.md).
<a name="form_query_parameters"></a>
## Handling Requests: Form/Query Parameter
[Handling Requests: Form/Query Parameter] (/workbook/handling_request/form.md).
[Handling Requests: Form/Query Parameter] (/doc/workbook/handling_request/form.md).
<a name="header_fields"></a>
## Handling Requests: Header Fields
[Handling Requests: Header Fields](/workbook/handling_request/headers.md).
[Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md).
<a name="header_fields"></a>
## Generating Response
[Generating Responses](/workbook/generating_response/generating_response.md)
[Generating Responses](/doc/workbook/generating_response/generating_response.md)
## Handling Cookies
[Handling Cookies](/workbook/handling_cookies/handling_cookies.md)
[Handling Cookies](/doc/workbook/handling_cookies/handling_cookies.md)

View File

@@ -24,7 +24,7 @@ feature {NONE} -- Initialization
setup_router
do
-- router.map (create {WSF_URI_MAPPING}.make ("/hello", create {WSF_AGENT_URI_HANDLER}.make (agent execute_hello)))
map_uri_agent ("/hello", agent execute_hello)
map_uri_agent ("/hello", agent execute_hello, Void)
-- router.map (create {WSF_URI_TEMPLATE_MAPPING}.make ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}), router.methods_HEAD_GET_POST)
map_uri_template ("/users/{user}/message/{mesgid}", create {USER_MESSAGE_HANDLER}, router.methods_HEAD_GET_POST)

View File

@@ -122,8 +122,8 @@ feature {NONE} -- Internal
feature -- Conversion to string
yyyy_mmm_dd_string: STRING
-- String representation YYYY mmm dd
-- 2012 Dec 25
-- String representation [YYYY mmm dd]
-- ex: 2012 Dec 25
do
create Result.make (11)
append_date_time_to_yyyy_mmm_dd_string (date_time, Result)
@@ -131,7 +131,8 @@ feature -- Conversion to string
rfc1123_string: STRING
-- String representation following RFC 1123.
--| Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
-- format: [ddd, dd mmm yyyy hh:mi:ss GMT]
-- ex: Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
local
s: like internal_rfc1123_string
do
@@ -145,7 +146,8 @@ feature -- Conversion to string
end
rfc850_string: STRING
-- String representation following RFC 850
-- String representation following RFC 850.
-- format: [mmm, dd-mmm-yy hh:mi:ss GMT]
do
create Result.make (32)
append_date_time_to_rfc850_string (date_time, Result)
@@ -153,6 +155,7 @@ feature -- Conversion to string
ansi_c_string: STRING
-- ANSI C's asctime() format
--| Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
do
create Result.make (32)
append_date_time_to_ansi_c_string (date_time, Result)
@@ -161,74 +164,34 @@ feature -- Conversion to string
feature -- Conversion into string
append_to_yyyy_mmm_dd_string (s: STRING_GENERAL)
local
dt: DATE_TIME
-- Append `datetime' as [yyyy mmm dd] format to `s'.
do
dt := date_time
append_integer_to (dt.year, s) -- yyyy
s.append_code (32) -- 32 ' ' -- SPace
append_month_mmm_to (dt.month, s) -- mmm
s.append_code (32) -- 32 ' ' -- SPace
append_2_digits_integer_to (dt.day, s) -- dd
append_date_time_to_yyyy_mmm_dd_string (date_time, s)
end
append_to_rfc1123_string (s: STRING_GENERAL)
local
dt: DATE_TIME
-- Append `date_time' as [ddd, dd mmm yyyy hh:mi:ss GMT] format to `s'.
do
dt := date_time
append_day_ddd_to (dt.date.day_of_the_week, s) -- ddd
s.append_code (44) -- 44 ',' -- ','
s.append_code (32) -- 32 ' ' -- SPace
append_2_digits_integer_to (dt.day, s) -- dd
s.append_code (32) -- 32 ' ' -- SPace
append_month_mmm_to (dt.month, s) -- mmm
s.append_code (32) -- 32 ' ' -- SPace
append_integer_to (dt.year, s) -- YYYY
s.append_code (32) -- 32 ' ' -- SPace
append_2_digits_time_to (dt.time, s) -- hh:mi:ss
s.append (" GMT") -- SPace + GMT
append_date_time_to_rfc1123_string (date_time, s)
end
append_rfc850_string (s: STRING_GENERAL)
local
dt: DATE_TIME
-- Append `date_time' as [mmm, dd-mmm-yy hh:mi:ss GMT] format to `s'.
do
dt := date_time
append_day_name_to (dt.date.day_of_the_week, s) -- mmm
s.append_code (44) -- 44 ',' -- ','
s.append_code (32) -- 32 ' ' -- SPace
append_2_digits_integer_to (dt.day, s) -- dd
s.append_code (45) -- 45 '-' -- '-'
append_month_mmm_to (dt.month, s) -- mmm
s.append_code (45) -- 45 '-' -- '-'
append_integer_to (dt.year \\ 100, s) -- yy
s.append_code (32) -- 32 ' ' -- SPace
append_2_digits_time_to (dt.time, s) -- hh:mi:ss
s.append (" GMT") -- SPace + GMT
append_date_time_to_rfc850_string (date_time, s)
end
append_to_ansi_c_string (s: STRING_GENERAL)
-- Append `date_time' as ANSI C's asctime format to `s'.
--| Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
local
dt: DATE_TIME
do
dt := date_time
append_day_ddd_to (dt.date.day_of_the_week, s) -- ddd
s.append_code (32) -- 32 ' ' -- SPace
append_month_mmm_to (dt.month, s) -- mmm
s.append_code (32) -- 32 ' ' -- SPace
s.append_code (32) -- 32 ' ' -- SPace
append_integer_to (dt.day, s) -- d
s.append_code (32) -- 32 ' ' -- SPace
append_2_digits_time_to (dt.time, s) -- hh:mi:ss
s.append_code (32) -- 32 ' ' -- SPace
append_integer_to (dt.year, s) -- yyyy
append_date_time_to_ansi_c_string (date_time, s)
end
feature -- Conversion into string
append_date_time_to_yyyy_mmm_dd_string (dt: DATE_TIME; s: STRING_GENERAL)
-- Append `dt' as [yyyy mmm dd] format to `s'.
do
append_integer_to (dt.year, s) -- yyyy
s.append_code (32) -- 32 ' ' -- SPace
@@ -238,6 +201,7 @@ feature -- Conversion into string
end
append_date_time_to_rfc1123_string (dt: DATE_TIME; s: STRING_GENERAL)
-- Append `dt' as [ddd, dd mmm yyyy hh:mi:ss GMT] format to `s'.
do
append_day_ddd_to (dt.date.day_of_the_week, s) -- ddd
s.append_code (44) -- 44 ',' -- ','
@@ -253,6 +217,7 @@ feature -- Conversion into string
end
append_date_time_to_rfc850_string (dt: DATE_TIME; s: STRING_GENERAL)
-- Append `dt' as [mmm, dd-mmm-yy hh:mi:ss GMT] format to `s'.
do
append_day_name_to (dt.date.day_of_the_week, s) -- mmm
s.append_code (44) -- 44 ',' -- ','
@@ -268,7 +233,8 @@ feature -- Conversion into string
end
append_date_time_to_ansi_c_string (dt: DATE_TIME; s: STRING_GENERAL)
--| Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
-- Append `dt' as ANSI C's asctime format to `s'.
-- Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
do
append_day_ddd_to (dt.date.day_of_the_week, s) -- ddd
s.append_code (32) -- 32 ' ' -- SPace
@@ -294,7 +260,7 @@ feature -- Status report
end
end
feature {NONE} -- Implementation
feature -- Helper routines.
append_2_digits_integer_to (i: INTEGER; s: STRING_GENERAL)
require
@@ -361,7 +327,7 @@ feature {NONE} -- Implementation
when 5 then s.append ("May")
when 6 then s.append ("Jun")
when 7 then s.append ("Jul")
when 8 then s.append ("Aou")
when 8 then s.append ("Aug")
when 9 then s.append ("Sep")
when 10 then s.append ("Oct")
when 11 then s.append ("Nov")
@@ -487,7 +453,7 @@ feature {NONE} -- Implementation
elseif l_mmm.same_string ("MAY") then l_mo := 05
elseif l_mmm.same_string ("JUN") then l_mo := 06
elseif l_mmm.same_string ("JUL") then l_mo := 07
elseif l_mmm.same_string ("AOU") then l_mo := 08
elseif l_mmm.same_string ("AUG") then l_mo := 08
elseif l_mmm.same_string ("SEP") then l_mo := 09
elseif l_mmm.same_string ("OCT") then l_mo := 10
elseif l_mmm.same_string ("NOV") then l_mo := 11
@@ -599,7 +565,11 @@ feature {NONE} -- Implementation
t.extend (s[i].as_upper)
i := i + 1
end
if t.same_string ("GMT") or t.same_string ("UTC") then
if
t.same_string ("GMT") -- for instance: GMT+0002
or t.same_string ("UTC") -- for instance: UTC+0002
or t.is_empty -- for instance: +0002
then
from until i > n or else not s[i].is_space loop i := i + 1 end
if i <= n then
t.wipe_out
@@ -718,7 +688,7 @@ feature {NONE} -- Implementation
elseif l_mmm.same_string ("MAY") then l_mo := 05
elseif l_mmm.same_string ("JUN") then l_mo := 06
elseif l_mmm.same_string ("JUL") then l_mo := 07
elseif l_mmm.same_string ("AOU") then l_mo := 08
elseif l_mmm.same_string ("AUG") then l_mo := 08
elseif l_mmm.same_string ("SEP") then l_mo := 09
elseif l_mmm.same_string ("OCT") then l_mo := 10
elseif l_mmm.same_string ("NOV") then l_mo := 11
@@ -905,7 +875,7 @@ feature {NONE} -- Implementation
invariant
note
copyright: "2011-2013, Jocelyn Fiat, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="notification_email" uuid="99D9A065-CD45-4E20-9C86-579C8AD42E5E" library_target="notification_email">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-14-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-14-0 http://www.eiffel.com/developers/xml/configuration-1-14-0.xsd" name="notification_email" uuid="99D9A065-CD45-4E20-9C86-579C8AD42E5E" library_target="notification_email">
<target name="notification_email">
<root all_classes="true"/>
<file_rule>
@@ -11,8 +11,20 @@
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="..\..\..\network\protocol\http\http-safe.ecf"/>
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf">
<condition>
<custom name="smtp_notification_email_disabled" excluded_value="true"/>
</condition>
</library>
<library name="process" location="$ISE_LIBRARY\library\process\process-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<cluster name="src" location=".\" recursive="true"/>
<cluster name="src" location=".\" >
<cluster name="storage" location="$|storage"/>
<cluster name="smtp" location="$|smtp">
<condition>
<custom name="smtp_notification_email_disabled" excluded_value="true"/>
</condition>
</cluster>
</cluster>
</target>
</system>

View File

@@ -2,9 +2,9 @@ note
description : "[
Component representing an email
]"
author : "$Author$"
date : "$Date$"
revision : "$Revision$"
author : "$Author: jfiat $"
date : "$Date: 2015-06-30 11:07:17 +0200 (mar., 30 juin 2015) $"
revision : "$Revision: 97586 $"
class
NOTIFICATION_EMAIL
@@ -14,15 +14,17 @@ create
feature {NONE} -- Initialization
make (a_from: like from_address; a_to_address: READABLE_STRING_8; a_subject: like subject; a_body: like body)
make (a_from: like from_address; a_to_address: READABLE_STRING_8; a_subject: like subject; a_content: like content)
-- Initialize `Current'.
require
well_formed_from_address: is_valid_address (a_from)
well_formed_to_address: a_to_address.has ('@')
do
initialize
from_address := a_from
subject := a_subject
body := a_body
content := a_content
to_addresses.extend (a_to_address)
end
initialize
@@ -37,11 +39,36 @@ feature -- Access
from_address: READABLE_STRING_8
reply_to_address: detachable READABLE_STRING_8
to_addresses: ARRAYED_LIST [READABLE_STRING_8]
cc_addresses: detachable ARRAYED_LIST [READABLE_STRING_8]
bcc_addresses: detachable ARRAYED_LIST [READABLE_STRING_8]
subject: READABLE_STRING_8
body: READABLE_STRING_8
content: READABLE_STRING_8
additional_header_lines: detachable ARRAYED_LIST [READABLE_STRING_8]
-- Additional header lines.
body: like content
obsolete
"Use `content' [June/2015]"
do
Result := body
end
feature -- Status report
is_valid: BOOLEAN
-- Is current email ready to be sent?
do
Result := is_valid_address (from_address) and
across to_addresses as ic all is_valid_address (ic.item) end
end
feature -- Change
@@ -50,13 +77,90 @@ feature -- Change
date := d
end
set_subject (s: READABLE_STRING_8)
-- Set `subject' to `s'.
do
subject := s
end
set_content (s: READABLE_STRING_8)
-- Set `content' to `s'.
do
content := s
end
set_from_address (add: READABLE_STRING_8)
require
well_formed_address: add.has ('@')
do
from_address := add
end
add_cc_address (add: READABLE_STRING_8)
require
well_formed_address: add.has ('@')
local
lst: like cc_addresses
do
lst := cc_addresses
if lst = Void then
create lst.make (1)
cc_addresses := lst
end
lst.force (add)
end
add_bcc_address (add: READABLE_STRING_8)
require
well_formed_address: add.has ('@')
local
lst: like bcc_addresses
do
lst := bcc_addresses
if lst = Void then
create lst.make (1)
bcc_addresses := lst
end
lst.force (add)
end
add_header_line (a_line: READABLE_STRING_8)
require
well_formed_header_line: a_line.has (':')
local
lst: like additional_header_lines
do
lst := additional_header_lines
if lst = Void then
create lst.make (1)
additional_header_lines := lst
end
lst.force (a_line)
end
feature -- Reset
reset
do
reset_addresses
additional_header_lines := Void
end
reset_addresses
-- Reset all addresses.
do
to_addresses.wipe_out
cc_addresses := Void
bcc_addresses := Void
end
feature -- Conversion
message: STRING_8
do
Result := header
Result.append_character ('%N')
Result.append (body)
Result.append (content)
Result.append_character ('%N')
Result.append_character ('%N')
end
@@ -66,13 +170,14 @@ feature -- Conversion
hdate: HTTP_DATE
do
create Result.make (20)
if attached reply_to_address as l_reply_to then
Result.append ("Reply-To: ")
Result.append (l_reply_to)
Result.append_character ('%N')
end
Result.append ("From: ")
Result.append (from_address)
Result.append_character ('%N')
Result.append ("Date: ")
create hdate.make_from_date_time (date)
hdate.append_to_rfc1123_string (Result)
Result.append (" GMT%N")
Result.append ("To: ")
across
to_addresses as c
@@ -81,18 +186,67 @@ feature -- Conversion
Result.append_character (';')
end
Result.append_character ('%N')
if
attached cc_addresses as l_cc and then
not l_cc.is_empty
then
Result.append ("Cc: ")
across
l_cc as c
loop
Result.append (c.item)
Result.append_character (';')
end
Result.append_character ('%N')
end
if
attached bcc_addresses as l_bcc and then
not l_bcc.is_empty
then
Result.append ("Bcc: ")
across
l_bcc as c
loop
Result.append (c.item)
Result.append_character (';')
end
Result.append_character ('%N')
end
Result.append ("Subject: ")
Result.append (subject)
Result.append_character ('%N')
Result.append ("Date: ")
create hdate.make_from_date_time (date)
hdate.append_to_rfc1123_string (Result)
Result.append_character ('%N')
if attached additional_header_lines as l_lines and then
not l_lines.is_empty
then
across
l_lines as ic
loop
Result.append (ic.item)
Result.append_character ('%N')
end
end
ensure
Result.ends_with ("%N")
end
feature -- Helpers
is_valid_address (add: READABLE_STRING_8): BOOLEAN
-- Is `add' a valid email address?
do
-- FIXME: improve email validation
Result := add.has ('@')
end
invariant
-- invariant_clause: True
note
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -11,8 +11,20 @@
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="http" location="..\..\..\network\protocol\http\http.ecf"/>
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf">
<condition>
<custom name="smtp_notification_email_disabled" excluded_value="true"/>
</condition>
</library>
<library name="process" location="$ISE_LIBRARY\library\process\process.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
<cluster name="src" location="." recursive="true"/>
<cluster name="src" location=".">
<cluster name="storage" location="$|storage"/>
<cluster name="smtp" location="$|smtp">
<condition>
<custom name="smtp_notification_email_disabled" excluded_value="true"/>
</condition>
</cluster>
</cluster>
</target>
</system>

View File

@@ -2,9 +2,9 @@ note
description: "[
Component responsible to send email
]"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
author: "$Author: jfiat $"
date: "$Date: 2015-06-30 11:07:17 +0200 (mar., 30 juin 2015) $"
revision: "$Revision: 97586 $"
deferred class
NOTIFICATION_MAILER
@@ -45,8 +45,40 @@ feature -- Basic operation
deferred
end
feature -- Error
has_error: BOOLEAN
-- Previous operation reported error?
-- Use `reset_errors', to reset this state.
do
Result := attached last_errors as lst and then not lst.is_empty
end
reset_errors
-- Reset last errors.
do
last_errors := Void
end
last_errors: detachable ARRAYED_LIST [READABLE_STRING_32]
-- Last reported errors since previous `reset_errors' call.
report_error (a_msg: READABLE_STRING_GENERAL)
-- Report error message `a_msg'.
local
lst: like last_errors
do
lst := last_errors
if lst = Void then
create lst.make (1)
last_errors := lst
end
lst.force (a_msg.to_string_32)
end
note
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -0,0 +1,34 @@
note
description: "Mailer that does nothing."
date: "$Date: 2015-06-30 15:49:56 +0200 (mar., 30 juin 2015) $"
revision: "$Revision: 97588 $"
class
NOTIFICATION_NULL_MAILER
inherit
NOTIFICATION_MAILER
feature -- Status
is_available: BOOLEAN = True
-- <Precursor>
feature -- Basic operation
process_email (a_email: NOTIFICATION_EMAIL)
-- <Precursor>
do
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -2,9 +2,9 @@ note
description : "[
NOTIFICATION_MAILER using sendmail as mailtool
]"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
author: "$Author: jfiat $"
date: "$Date: 2015-06-30 15:49:56 +0200 (mar., 30 juin 2015) $"
revision: "$Revision: 97588 $"
class
NOTIFICATION_SENDMAIL_MAILER
@@ -16,23 +16,29 @@ inherit
end
create
default_create
default_create,
make_with_location
feature {NONE} -- Initialization
make_with_location (a_path: READABLE_STRING_GENERAL)
do
make (a_path, <<"-t">>)
set_stdin_mode (True, "%N.%N%N")
end
default_create
do
Precursor
make ("/usr/sbin/sendmail", <<"-t">>)
make_with_location ("/usr/sbin/sendmail")
if not is_available then
make ("/usr/bin/sendmail", <<"-t">>)
make_with_location ("/usr/bin/sendmail")
end
set_stdin_mode (True, "%N.%N%N")
end
note
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -0,0 +1,54 @@
note
description: "Summary description for {NOTIFICATION_STORAGE_MAILER}."
author: ""
date: "$Date: 2015-06-30 15:49:56 +0200 (mar., 30 juin 2015) $"
revision: "$Revision: 97588 $"
class
NOTIFICATION_STORAGE_MAILER
inherit
NOTIFICATION_MAILER
create
make
feature {NONE} -- Initialization
make (a_storage: NOTIFICATION_EMAIL_STORAGE)
do
storage := a_storage
end
storage: NOTIFICATION_EMAIL_STORAGE
feature -- Status report
is_available: BOOLEAN
-- <Precursor>
do
Result := storage.is_available
end
feature -- Basic operation
process_email (a_email: NOTIFICATION_EMAIL)
-- <Precursor>
do
storage.put (a_email)
if storage.has_error then
report_error ("Issue storing email.")
end
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -0,0 +1,181 @@
note
description: "[
Notification mailer based on STMP protocol.
Note: it is based on EiffelNet {SMTP_PROTOCOL} implementation, and may not be complete.
]"
author: "$Author: jfiat $"
date: "$Date: 2015-06-30 11:07:17 +0200 (mar., 30 juin 2015) $"
revision: "$Revision: 97586 $"
class
NOTIFICATION_SMTP_MAILER
inherit
NOTIFICATION_MAILER
create
make,
make_with_user
feature {NONE} -- Initialization
make (a_smtp_server: READABLE_STRING_8)
do
make_with_user (a_smtp_server, Void, Void)
end
make_with_user (a_smtp_server: READABLE_STRING_8; a_user: detachable READABLE_STRING_8; a_password: detachable READABLE_STRING_8)
-- Initialize `Current'.
local
i: INTEGER
do
i := a_smtp_server.index_of (':', 1)
if i > 0 then
smtp_host := a_smtp_server.substring (1, i - 1)
smtp_port := a_smtp_server.substring (i + 1, a_smtp_server.count).to_integer
else
smtp_host := a_smtp_server
smtp_port := 0
end
username := a_user
initialize
end
initialize
-- Initialize service.
local
l_address_factory: INET_ADDRESS_FACTORY
do
if attached username as u then
create smtp_protocol.make (smtp_host, u)
else
-- Get local host name needed in creation of SMTP_PROTOCOL.
create l_address_factory
create smtp_protocol.make (smtp_host, l_address_factory.create_localhost.host_name)
end
if smtp_port > 0 then
smtp_protocol.set_default_port (smtp_port)
end
reset_errors
end
smtp_protocol: SMTP_PROTOCOL
-- SMTP protocol.
feature -- Access
smtp_host: READABLE_STRING_8
smtp_port: INTEGER
username: detachable READABLE_STRING_8
feature -- Status
is_available: BOOLEAN
do
Result := True
end
feature -- Basic operation
process_email (a_email: NOTIFICATION_EMAIL)
-- Process the sending of `a_email'
local
l_email: EMAIL
h: STRING
k,v: STRING
i: INTEGER
hdate: HTTP_DATE
do
create l_email.make_with_entry (a_email.from_address, addresses_to_header_line_value (a_email.to_addresses))
if attached a_email.reply_to_address as l_reply_to then
l_email.add_header_entry ({EMAIL_CONSTANTS}.h_reply_to, l_reply_to)
end
if attached a_email.cc_addresses as lst then
l_email.add_header_entry ({EMAIL_CONSTANTS}.h_cc, addresses_to_header_line_value (lst))
end
if attached a_email.bcc_addresses as lst then
l_email.add_header_entry ({EMAIL_CONSTANTS}.h_bcc, addresses_to_header_line_value (lst))
end
l_email.set_message (a_email.content)
l_email.add_header_entry ({EMAIL_CONSTANTS}.H_subject, a_email.subject)
create h.make_empty
create hdate.make_from_date_time (a_email.date)
hdate.append_to_rfc1123_string (h)
l_email.add_header_entry ("Date", h)
if attached a_email.additional_header_lines as lst then
across
lst as ic
loop
h := ic.item
i := h.index_of (':', 1)
if i > 0 then
k := h.head (i - 1)
v := h.substring (i + 1, h.count)
l_email.add_header_entry (k, v)
else
check is_header_line: False end
end
end
end
smtp_send_email (l_email)
end
feature {NONE} -- Implementation
addresses_to_header_line_value (lst: ITERABLE [READABLE_STRING_8]): STRING
local
l_need_separator: BOOLEAN
do
create Result.make (10)
l_need_separator := False
across
lst as ic
loop
if l_need_separator then
Result.append_character (',')
Result.append_character (' ')
else
l_need_separator := True
end
Result.append (ic.item)
end
end
smtp_send_email (a_email: EMAIL)
-- Send the email represented by `a_email'.
local
retried: BOOLEAN
do
if not retried then
smtp_protocol.initiate_protocol
smtp_protocol.transfer (a_email)
smtp_protocol.close_protocol
if smtp_protocol.error then
report_error ("smtp_protocol reported an error.")
end
end
rescue
report_error ("smtp_protocol raised an exception.")
retried := True
retry
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -0,0 +1,74 @@
note
description: "Store email in specific file (could also be stderr, ...)."
date: "$Date: 2015-06-30 15:49:56 +0200 (mar., 30 juin 2015) $"
revision: "$Revision: 97588 $"
class
NOTIFICATION_EMAIL_FILE_STORAGE
inherit
NOTIFICATION_EMAIL_STORAGE
create
make
feature {NONE} -- Initialization
make (a_output_file: FILE)
require
a_output_file_valid: a_output_file.exists
do
output := a_output_file
end
output: FILE
feature -- Status report
is_available: BOOLEAN
-- Is associated storage available?
do
Result := output.exists and output.is_access_writable
end
has_error: BOOLEAN
-- Last operation reported an error?
feature -- Storage
put (a_email: NOTIFICATION_EMAIL)
-- Store `a_email'.
local
retried: BOOLEAN
l_close_needed: BOOLEAN
do
if not retried then
has_error := False
if not output.is_open_write then
output.open_write
l_close_needed := True
end
output.put_string ("%N----%N" + a_email.message)
if l_close_needed then
output.close
else
output.flush
end
end
rescue
retried := True
has_error := True
retry
end
;note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -0,0 +1,38 @@
note
description: "Abtract interface of email storage."
date: "$Date: 2015-06-30 15:49:56 +0200 (mar., 30 juin 2015) $"
revision: "$Revision: 97588 $"
deferred class
NOTIFICATION_EMAIL_STORAGE
feature -- Status report
is_available: BOOLEAN
-- Is associated storage available?
deferred
end
has_error: BOOLEAN
-- Last operation reported an error?
deferred
end
feature -- Storage
put (a_email: NOTIFICATION_EMAIL)
-- Store `a_email'.
deferred
end
note
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -81,7 +81,7 @@ feature -- Element change
-- Unset `http_server_name' value.
do
http_server_name := Void
ensure
ensure
unset_http_server_name: http_server_name = Void
end
@@ -202,11 +202,6 @@ feature -- SSL Helpers
deferred
end
set_ssl_protocol_to_ssl_3
-- Set `ssl_protocol' with `Ssl_3'.
deferred
end
set_ssl_protocol_to_tls_1_0
-- Set `ssl_protocol' with `Tls_1_0'.
deferred

View File

@@ -60,7 +60,6 @@ feature -- Access
is_persistent_connection_supported: BOOLEAN = True
-- Is persistent connection supported?
--| For now, disabled during dev.
feature -- Callbacks

View File

@@ -27,11 +27,6 @@ feature -- SSL Helpers
-- Ignored
end
set_ssl_protocol_to_ssl_3
-- Set `ssl_protocol' with `Ssl_3'.
do
-- Ignored
end
set_ssl_protocol_to_tls_1_0
-- Set `ssl_protocol' with `Tls_1_0'.

View File

@@ -41,12 +41,6 @@ feature -- SSL Helpers
set_ssl_protocol ({SSL_PROTOCOL}.Ssl_23)
end
set_ssl_protocol_to_ssl_3
-- Set `ssl_protocol' with `Ssl_3'.
do
set_ssl_protocol ({SSL_PROTOCOL}.Ssl_3)
end
set_ssl_protocol_to_tls_1_0
-- Set `ssl_protocol' with `Tls_1_0'.
do

View File

@@ -87,6 +87,7 @@ feature -- Request processing
else
l_output.set_http_version (version)
end
res.set_is_persistent_connection_supported ({HTTPD_SERVER}.is_persistent_connection_supported)
res.set_is_persistent_connection_requested (is_persistent_connection_requested)
req.set_meta_string_variable ("RAW_HEADER_DATA", request_header)
@@ -111,22 +112,30 @@ feature -- Request processing
end
end
process_rescue (res: detachable WGI_RESPONSE)
local
s: STRING
do
if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.trace as l_trace then
if res /= Void then
if not res.status_is_set then
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void)
end
create s.make_empty
s.append ("<pre>")
s.append (html_encoder.encoded_string (l_trace))
s.append ("</pre>")
if not res.header_committed then
res.put_header_text ("Content-Type: text/html%R%NContent-Length: " + s.count.out + "%R%N%R%N")
end
if res.message_writable then
res.put_string ("<pre>")
res.put_string (html_encoder.encoded_string (l_trace))
res.put_string ("</pre>")
res.put_string (s)
end
res.push
end
end
end
end
httpd_environment (a_socket: HTTPD_STREAM_SOCKET): STRING_TABLE [READABLE_STRING_8]
local

View File

@@ -29,7 +29,7 @@ feature {NONE} -- Initialization
last_target_call_succeed := True
end
feature {WGI_STANDALONE_CONNECTOR, WGI_SERVICE} -- Nino
feature {WGI_STANDALONE_CONNECTOR, WGI_SERVICE} -- Server
set_target (o: like target)
do
@@ -100,7 +100,7 @@ feature -- Status report
-- <Precursor>
-- for instance IO failure due to socket disconnection.
do
Result := not last_target_call_succeed
Result := last_target_call_succeed
end
is_open_write: BOOLEAN

View File

@@ -23,6 +23,9 @@ feature -- Settings
is_http_version_1_0: BOOLEAN
-- Is associated request using HTTP/1.0 ?
is_persistent_connection_supported: BOOLEAN
-- Is persistent connection supported?
is_persistent_connection_requested: BOOLEAN
-- Is persistent connection requested?
@@ -34,6 +37,12 @@ feature -- Settings change
is_http_version_1_0 := True
end
set_is_persistent_connection_supported (b: BOOLEAN)
-- Set `is_persistent_connection_supported' to `b'.
do
is_persistent_connection_supported := b
end
set_is_persistent_connection_requested (b: BOOLEAN)
-- Set `is_persistent_connection_requested' to `b'.
do
@@ -53,7 +62,7 @@ feature -- Header output operation
create s.make_from_string (a_text)
i := s.substring_index ("%NConnection:", 1)
if {HTTPD_SERVER}.is_persistent_connection_supported then
if is_persistent_connection_supported then
-- Current standalone support persistent connection.
-- If HTTP/1.1:
-- by default all connection are persistent

View File

@@ -0,0 +1,23 @@
package ewsgi
project
ewsgi = "ewsgi-safe.ecf"
ewsgi = "ewsgi.ecf"
ewsgi_spec = "ewsgi_spec-safe.ecf"
ewsgi_spec = "ewsgi_spec.ecf"
connector_cgi = "connectors/cgi/cgi-safe.ecf"
connector_cgi = "connectors/cgi/cgi.ecf"
connector_libfcgi = "connectors/libfcgi/libfcgi-safe.ecf"
connector_libfcgi = "connectors/libfcgi/libfcgi.ecf"
connector_nino = "connectors/nino/nino-safe.ecf"
connector_nino = "connectors/nino/nino.ecf"
connector_null = "connectors/null/null-safe.ecf"
connector_null = "connectors/null/null.ecf"
note
title: EWSGI
description: EWSGI specification, and a few connectors.
tags: web, httpd, ewf
license: Eiffel Forum v2
end

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="connector_libfcgi_v0" uuid="59C57E56-3EE6-4EF7-873F-7ED084B0EB22" library_target="connector_libfcgi_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="connector_libfcgi_v0" uuid="5E1C9860-2D9E-4A94-A11D-DA0FD9B31470" library_target="connector_libfcgi_v0">
<target name="connector_libfcgi_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="connector_libfcgi_v0" uuid="59C57E56-3EE6-4EF7-873F-7ED084B0EB22" library_target="connector_libfcgi_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="connector_libfcgi_v0" uuid="5E1C9860-2D9E-4A94-A11D-DA0FD9B31470" library_target="connector_libfcgi_v0">
<target name="connector_libfcgi_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="connector_nino_v0" uuid="F91861FB-4FEA-455F-9570-828D7903DC64" library_target="connector_nino_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="connector_nino_v0" uuid="6E00FB27-C0E2-4859-93A0-BF516C44C95F" library_target="connector_nino_v0">
<target name="connector_nino_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="connector_nino_v0" uuid="F91861FB-4FEA-455F-9570-828D7903DC64" library_target="connector_nino_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="connector_nino_v0" uuid="6E00FB27-C0E2-4859-93A0-BF516C44C95F" library_target="connector_nino_v0">
<target name="connector_nino_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_libfcgi_v0" uuid="00B169F1-2BE2-4986-8B93-825FEB944FFD" library_target="wsf_libfcgi_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_libfcgi_v0" uuid="36DB043B-E4E9-4BB6-936C-3564335C34EF" library_target="wsf_libfcgi_v0">
<target name="wsf_libfcgi_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_libfcgi_v0" uuid="00B169F1-2BE2-4986-8B93-825FEB944FFD" library_target="wsf_libfcgi_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_libfcgi_v0" uuid="36DB043B-E4E9-4BB6-936C-3564335C34EF" library_target="wsf_libfcgi_v0">
<target name="wsf_libfcgi_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wsf_nino_v0" uuid="BACF0220-900B-4409-8CB2-30A09836A650" library_target="wsf_nino_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wsf_nino_v0" uuid="81525F4F-7BCA-471B-B1E3-2601EFD242E0" library_target="wsf_nino_v0">
<target name="wsf_nino_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wsf_nino_v0" uuid="BACF0220-900B-4409-8CB2-30A09836A650" library_target="wsf_nino_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wsf_nino_v0" uuid="81525F4F-7BCA-471B-B1E3-2601EFD242E0" library_target="wsf_nino_v0">
<target name="wsf_nino_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="default_libfcgi_v0" uuid="B853CC3A-D173-4DA4-9832-6D0148C8F01F" library_target="default_libfcgi_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="default_libfcgi_v0" uuid="757C822A-6A23-42E6-9A30-2B0977960E3D" library_target="default_libfcgi_v0">
<target name="default_libfcgi_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="default_libfcgi_v0" uuid="B853CC3A-D173-4DA4-9832-6D0148C8F01F" library_target="default_libfcgi_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="default_libfcgi_v0" uuid="757C822A-6A23-42E6-9A30-2B0977960E3D" library_target="default_libfcgi_v0">
<target name="default_libfcgi_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="default_nino_v0" uuid="ACBEDC97-956C-45F5-97E3-65A6D9987625" library_target="default_nino_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="default_nino_v0" uuid="D3606AED-7593-460A-94FD-2859C71386FF" library_target="default_nino_v0">
<target name="default_nino_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="default_nino_v0" uuid="ACBEDC97-956C-45F5-97E3-65A6D9987625" library_target="default_nino_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="default_nino_v0" uuid="D3606AED-7593-460A-94FD-2859C71386FF" library_target="default_nino_v0">
<target name="default_nino_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_extension_v0" uuid="11055B92-CBEF-4272-8B50-0450BDA154E5" library_target="wsf_extension_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_extension_v0" uuid="66FC8180-27E6-4335-B571-4D38D3BC633A" library_target="wsf_extension_v0">
<target name="wsf_extension_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_extension_v0" uuid="11055B92-CBEF-4272-8B50-0450BDA154E5" library_target="wsf_extension_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_extension_v0" uuid="66FC8180-27E6-4335-B571-4D38D3BC633A" library_target="wsf_extension_v0">
<target name="wsf_extension_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="wsf_policy_driven_v0" uuid="3FC00449-5101-461D-94C6-10920C30EBF4" library_target="wsf_policy_driven_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="wsf_policy_driven_v0" uuid="E175F999-1164-48AA-83E1-6C14FC5E8C82" library_target="wsf_policy_driven_v0">
<target name="wsf_policy_driven_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="wsf_policy_driven_v0" uuid="3FC00449-5101-461D-94C6-10920C30EBF4" library_target="wsf_policy_driven_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="wsf_policy_driven_v0" uuid="E175F999-1164-48AA-83E1-6C14FC5E8C82" library_target="wsf_policy_driven_v0">
<target name="wsf_policy_driven_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_router_context_v0" uuid="1A0F9B0E-26CE-4DE0-BE47-C74D1AB2B389" library_target="wsf_router_context_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_router_context_v0" uuid="BA6468F6-2130-45FC-A2F7-26A7781B09CE" library_target="wsf_router_context_v0">
<target name="wsf_router_context_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_router_context_v0" uuid="1A0F9B0E-26CE-4DE0-BE47-C74D1AB2B389" library_target="wsf_router_context_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_router_context_v0" uuid="BA6468F6-2130-45FC-A2F7-26A7781B09CE" library_target="wsf_router_context_v0">
<target name="wsf_router_context_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,3 +1,3 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<redirection xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" uuid="C41D0367-9852-4AA7-9E7E-DEA162A4CBB0" location="../../../wsf/wsf_session-safe.ecf">
<redirection xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" uuid="74D6AAE4-1AF5-4D5C-B19D-D24383B7DE93" location="../../../wsf/wsf_session-safe.ecf">
</redirection>

View File

@@ -1,3 +1,3 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<redirection xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" uuid="C41D0367-9852-4AA7-9E7E-DEA162A4CBB0" location="../../../wsf/wsf_session.ecf">
<redirection xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" uuid="74D6AAE4-1AF5-4D5C-B19D-D24383B7DE93" location="../../../wsf/wsf_session.ecf">
</redirection>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_html_v0" uuid="6AAAE037-7E66-4F5D-BED0-0042245C26BC" library_target="wsf_html_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_html_v0" uuid="9D0DC2A2-BE67-4499-B730-87C7DDE25860" library_target="wsf_html_v0">
<target name="wsf_html_v0">
<root all_classes="true"/>
<file_rule>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="wsf_html_v0" uuid="6AAAE037-7E66-4F5D-BED0-0042245C26BC" library_target="wsf_html_v0">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_html_v0" uuid="9D0DC2A2-BE67-4499-B730-87C7DDE25860" library_target="wsf_html_v0">
<target name="wsf_html_v0">
<root all_classes="true"/>
<file_rule>
@@ -9,13 +9,14 @@
</file_rule>
<option warning="true" full_class_checking="true" void_safety="none" syntax="standard">
</option>
<library name="base" location="$ISE_LIBRARY/library/base/base.ecf"/>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="encoder" location="../../../../text/encoder/encoder.ecf"/>
<library name="uri_template" location="../../../../text/parser/uri_template/uri_template.ecf"/>
<library name="wsf" location="../wsf/wsf.ecf"/>
<cluster name="form" location="./form" recursive="true"/>
<cluster name="widget" location="./widget" recursive="true"/>
<cluster name="css" location="./css" recursive="true"/>
<cluster name="api" location="./api" recursive="true"/>
<library name="wsf" location="..\wsf\wsf.ecf"/>
<cluster name="api" location="..\..\..\wsf_html\api\" recursive="true"/>
<cluster name="css" location="..\..\..\wsf_html\css\" recursive="true"/>
<cluster name="form" location="..\..\..\wsf_html\form\" recursive="true"/>
<cluster name="widget" location="..\..\..\wsf_html\widget\" recursive="true"/>
</target>
</system>

View File

@@ -116,7 +116,7 @@ feature -- Output operation
end
note
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -1902,7 +1902,7 @@ feature -- URL Utility
elseif spos > 0 then
i := spos
end
spos := l_rq_uri.substring_index (path_info, i)
spos := l_rq_uri.substring_index (percent_encoded_path_info, i)
if spos > 0 then
l_base_url := l_rq_uri.substring (1, spos - 1)
else

View File

@@ -319,8 +319,8 @@ feature -- Header output operation: helpers
feature -- Header add cookie
add_cookie (a_cookie: WSF_COOKIE)
-- Add a Set-Cookie header field to the response, iff there is not exist
-- a Set-Cookie header field with the same cookie-name.
-- Add a Set-Cookie header field to the response,
-- if no Set-Cookie header field already use same cookie-name.
--| Servers SHOULD NOT include more than one Set-Cookie header field in
--| the same response with the same cookie-name.
local
@@ -328,7 +328,8 @@ feature -- Header add cookie
do
across
internal_header.headers as ic
until l_same_cookie_name
until
l_same_cookie_name
loop
if ic.item.starts_with ("Set-Cookie:") then
l_same_cookie_name := has_cookie_name (ic.item, a_cookie.name)
@@ -544,24 +545,29 @@ feature -- Error reporting
feature {NONE} -- Implemenation
has_cookie_name (a_cookie_line, a_cookie_name: READABLE_STRING_32 ): BOOLEAN
-- Has the cookie line `a_cookie_line', the cookie name `a_cookie_name'?
local
i,j: INTEGER
do
Result := False
i := a_cookie_line.index_of ('=', 1)
has_cookie_name (a_cookie_line, a_cookie_name: READABLE_STRING_GENERAL): BOOLEAN
-- Has the cookie line `a_cookie_line', the cookie name `a_cookie_name'?
local
i,j,n: INTEGER
do
j := a_cookie_line.index_of (':', 1)
if i > j and j > 0 then
i := i - 1
j := j + 1
from until not a_cookie_line[j].is_space loop
j := j + 1
end
if a_cookie_name.same_characters (a_cookie_line, j, i, 1) then
Result := True
end
if j > 0 then
i := a_cookie_line.index_of ('=', 1)
if i > j then
i := i - 1
j := j + 1
-- Skip spaces.
from
n := a_cookie_line.count
until
j > n or not a_cookie_line[j].is_space
loop
j := j + 1
end
if j > n then
Result := a_cookie_name.same_characters (a_cookie_line, j, i, 1)
end
end
end
end

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="wsf" uuid="A37CE5AA-4D2A-4441-BC6A-0A1D7EC49647" library_target="wsf">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="wsf" uuid="A37CE5AA-4D2A-4441-BC6A-0A1D7EC49647" library_target="wsf">
<target name="wsf">
<root all_classes="true"/>
<file_rule>
@@ -9,23 +9,23 @@
</file_rule>
<option warning="true" full_class_checking="true" void_safety="none" syntax="provisional">
</option>
<library name="base" location="$ISE_LIBRARY/library/base/base.ecf"/>
<mapping old_name="WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_EXECUTION" new_name="WSF_ROUTED_URI_TEMPLATE_HELPER"/>
<mapping old_name="WSF_URI_HELPER_FOR_ROUTED_EXECUTION" new_name="WSF_ROUTED_URI_HELPER"/>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension.ecf"/>
<library name="ewsgi" location="..\ewsgi\ewsgi.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
<library name="error" location="../../utility/general/error/error.ecf"/>
<library name="http" location="../../network/protocol/http/http.ecf"/>
<library name="conneg" location="..\..\network\protocol\content_negotiation\conneg.ecf"/>
<library name="uri_template"
location="../../text/parser/uri_template/uri_template.ecf"/>
<library name="encoder"
location="..\..\text\encoder\encoder.ecf"/>
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf" readonly="true"/>
<cluster name="src" location=".\src" recursive="true"/>
<cluster name="router" location=".\router" recursive="true">
<library name="encoder" location="..\..\text\encoder\encoder.ecf"/>
<library name="error" location="..\..\utility\general\error\error.ecf"/>
<library name="ewsgi" location="..\ewsgi\ewsgi.ecf"/>
<library name="http" location="..\..\network\protocol\http\http.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf"/>
<library name="uri_template" location="..\..\text\parser\uri_template\uri_template.ecf"/>
<cluster name="router" location=".\router\" recursive="true">
<file_rule>
<exclude>/policy_driven$</exclude>
</file_rule>
</cluster>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
</system>

View File

@@ -72,18 +72,28 @@ feature -- Change
set_value (v: detachable WSF_VALUE)
-- Set value `v' if applicable to Current
local
l_found: BOOLEAN
do
if attached {ITERABLE [WSF_VALUE]} v as lst then
across
lst as c
until
l_found
loop
set_checked_by_value (c.item)
if attached {WSF_STRING} c.item as s and then is_same_value (s.value) then
set_checked_by_value (c.item)
l_found := True
end
end
if not l_found then
set_checked (False)
end
else
set_checked_by_value (v)
Precursor (v)
end
end
end
feature {NONE} -- Implementation

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-14-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-14-0 http://www.eiffel.com/developers/xml/configuration-1-14-0.xsd" name="feed" uuid="71364A69-1549-472E-AF78-FDA4FDA016EB" library_target="feed">
<target name="feed">
<root all_classes="true"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<library name="uuid" location="$ISE_LIBRARY\library\uuid\uuid-safe.ecf"/>
<library name="xml_parser" location="$ISE_LIBRARY\library\text\parser\xml\parser\xml_parser-safe.ecf"/>
<library name="xml_tree" location="$ISE_LIBRARY\library\text\parser\xml\tree\xml_tree-safe.ecf"/>
<cluster name="src" location="src\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-14-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-14-0 http://www.eiffel.com/developers/xml/configuration-1-14-0.xsd" name="feed" uuid="71364A69-1549-472E-AF78-FDA4FDA016EB" library_target="feed">
<target name="feed">
<root all_classes="true"/>
<option void_safety="none">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
<library name="uuid" location="$ISE_LIBRARY\library\uuid\uuid.ecf"/>
<library name="xml_parser" location="$ISE_LIBRARY\library\text\parser\xml\parser\xml_parser.ecf"/>
<library name="xml_tree" location="$ISE_LIBRARY\library\text\parser\xml\tree\xml_tree.ecf"/>
<cluster name="src" location="src\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,186 @@
note
description: "Convert a FEED into an ATOM content."
date: "$Date$"
revision: "$Revision$"
class
ATOM_FEED_GENERATOR
inherit
FEED_VISITOR
FEED_GENERATOR
rename
process_feed as visit_feed
end
create
make
feature -- Visitor
visit_feed (a_feed: FEED)
do
buffer.append ("[
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
]")
buffer.append_character ('%N')
indent
append_content_tag_to ("title", Void, a_feed.title, buffer)
append_content_tag_to ("subtitle", Void, a_feed.description, buffer)
if attached a_feed.id as l_id then
append_content_tag_to ("id", Void, l_id, buffer)
else
append_content_tag_to ("id", Void, "urn:uuid:" + new_uuid, buffer)
end
across
a_feed.links as tb
loop
tb.item.accept (Current)
end
if attached a_feed.date as dt then
append_content_tag_to ("updated", Void, date_to_string (dt), buffer)
end
across
a_feed.items as ic
loop
ic.item.accept (Current)
end
exdent
buffer.append ("</feed>")
end
visit_item (a_entry: FEED_ITEM)
do
buffer.append (indentation)
buffer.append ("<entry>%N")
indent
append_content_tag_to ("title", Void, a_entry.title, buffer)
across
a_entry.links as tb
loop
tb.item.accept (Current)
end
if attached a_entry.id as l_id then
append_content_tag_to ("id", Void, l_id, buffer)
else
append_content_tag_to ("id", Void, "urn:uuid:" + new_uuid, buffer)
end
if attached a_entry.date as dt then
append_content_tag_to ("updated", Void, date_to_string (dt), buffer)
end
append_content_tag_to ("summary", Void, a_entry.description, buffer)
if attached a_entry.content as l_content then
if attached a_entry.content_type_or_default ("xhtml").is_case_insensitive_equal_general ("xhtml") then
-- if l_content.has_substring ("<div xmlns=%"http://www.w3.org/1999/xhtml%">") then
append_content_tag_to ("content", <<["type", "xhtml"]>>, l_content, buffer)
-- else
-- append_content_tag_to ("content", <<["type", "xhtml"]>>, {STRING_32} "<div xmlns=%"http://www.w3.org/1999/xhtml%">" + l_content + {STRING_32} "</div>", buffer)
-- end
else
append_content_tag_to ("content", <<["type", a_entry.content_type]>>, a_entry.content, buffer)
end
end
if attached a_entry.author as u then
u.accept (Current)
end
exdent
buffer.append (indentation)
buffer.append ("</entry>%N")
end
visit_link (a_link: FEED_LINK)
local
attr: detachable ARRAYED_LIST [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_32]]
tu: TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_32]
do
create attr.make (2)
if attached a_link.relation as rel and then not rel.is_whitespace then
tu := ["rel", rel]
attr.force (tu)
end
if attached a_link.type as t and then not t.is_whitespace then
tu := ["type", t.as_string_32]
attr.force (tu)
end
tu := ["href", a_link.href.as_string_32]
attr.force (tu)
if attr.is_empty then
attr := Void
end
append_content_tag_to ("link", attr, Void, buffer)
end
visit_author (a_author: FEED_AUTHOR)
do
buffer.append (indentation)
buffer.append ("<author>%N")
indent
append_content_tag_to ("name", Void, a_author.name, buffer)
append_content_tag_to ("email", Void, a_author.email, buffer)
exdent
buffer.append (indentation)
buffer.append ("</author>%N")
end
feature {NONE} -- Helpers
new_uuid: STRING
local
gen: UUID_GENERATOR
do
create gen
Result := gen.generate_uuid.out.as_lower
end
date_to_string (dt: DATE_TIME): STRING
do
Result := date_to_rfc3339_string (dt)
end
date_to_rfc3339_string (d: DATE_TIME): STRING
-- 2003-12-13T18:30:02Z
local
i: INTEGER
do
create Result.make_empty
Result.append_integer (d.year)
Result.append_character ('-')
i := d.month
if i < 10 then
Result.append_integer (0)
end
Result.append_integer (i)
Result.append_character ('-')
i := d.day
if i < 10 then
Result.append_integer (0)
end
Result.append_integer (i)
Result.append_character ('T')
i := d.hour
if i < 10 then
Result.append_integer (0)
end
Result.append_integer (i)
Result.append_character (':')
i := d.minute
if i < 10 then
Result.append_integer (0)
end
Result.append_integer (i)
Result.append_character (':')
i := d.second
if i < 10 then
Result.append_integer (0)
end
Result.append_integer (i)
Result.append_character ('Z')
end
end

View File

@@ -0,0 +1,104 @@
note
description: "[
ATOM Parser.
Warning: the implementation may not support the full ATOM specification.
]"
date: "$Date$"
revision: "$Revision$"
EIS: "name=ATOM at wikipedia", "protocol=URI", "src=https://en.wikipedia.org/wiki/Atom_(standard)"
EIS: "name=RSS at wikipedia", "protocol=URI", "src=https://en.wikipedia.org/wiki/RSS"
EIS: "name=ATOM 1.0 RFC4287", "protocol=URI", "src=https://tools.ietf.org/html/rfc4287"
class
ATOM_FEED_PARSER
inherit
FEED_PARSER
feature -- Access
name: STRING = "atom1"
-- Associated name.
is_detected (xdoc: XML_DOCUMENT): BOOLEAN
-- Is `xdoc' an ATOM feed representation?
do
Result := attached {XML_ELEMENT} xdoc.element_by_name ("feed") as x_feed and then
(
not attached xml_attribute_text (x_feed, "xmlns") as l_xmlns
or else l_xmlns.same_string ("http://www.w3.org/2005/Atom")
)
end
feed (xdoc: XML_DOCUMENT): detachable FEED
-- Feed from `xdoc' XML document.
local
l_title: READABLE_STRING_32
x_entry, x_link: detachable XML_ELEMENT
e: FEED_ITEM
l_author: FEED_AUTHOR
lnk: FEED_LINK
s: STRING_32
do
if
attached xdoc.element_by_name ("feed") as x_feed and then
-- (not attached xml_attribute_text (x_feed, "xmlns") as l_xmlns or else l_xmlns.same_string ("http://www.w3.org/2005/Atom"))
attached xml_element_text (x_feed, "title") as t
then
l_title := t
create Result.make (l_title)
Result.set_description (xml_element_text (x_feed, "subtitle"), "plain")
Result.set_id (xml_element_text (x_feed, "id"))
Result.set_updated_date_with_text (xml_element_text (x_feed, "updated"))
if attached links_from_xml (x_feed, "link") as l_links then
across
l_links as link_ic
loop
lnk := link_ic.item
Result.links.force (lnk, lnk.relation)
end
end
if attached x_feed.elements_by_name ("entry") as x_entries then
across
x_entries as ic
loop
x_entry := ic.item
if attached xml_element_text (x_entry, "title") as e_title then
create e.make (e_title)
e.set_description (xml_element_text (x_entry, "summary"))
e.set_id (xml_element_text (x_entry, "id"))
e.set_updated_date_with_text (xml_element_text (x_entry, "updated"))
if attached links_from_xml (x_entry, "link") as l_links then
across
l_links as link_ic
loop
lnk := link_ic.item
e.links.force (lnk, lnk.relation)
end
end
if attached x_entry.element_by_name ("content") as x_content then
e.set_content (xml_element_code (x_content), xml_attribute_text (x_content, "type"))
end
if attached x_entry.element_by_name ("author") as x_author then
if attached x_author.element_by_name ("name") as x_name and then
attached x_name.text as l_author_name
then
create l_author.make (l_author_name)
if attached x_author.element_by_name ("email") as x_email then
l_author.set_email (x_email.text)
end
e.set_author (l_author)
end
end
Result.extend (e)
end
end
end
end
end
end

View File

@@ -0,0 +1,69 @@
note
description: "[
Collection of default feed parsers provided by the current library.
A new parser can be easily added via `parsers.extend (...)'.
]"
date: "$Date$"
revision: "$Revision$"
class
FEED_DEFAULT_PARSERS
inherit
ANY
redefine
default_create
end
create
default_create
feature {NONE} -- Initialization
default_create
do
Precursor
create {ARRAYED_LIST [FEED_PARSER]} parsers.make (2)
parsers.force (create {RSS_2_FEED_PARSER})
parsers.force (create {ATOM_FEED_PARSER})
end
feature -- Access
parsers: LIST [FEED_PARSER]
-- Available Feed parsers.
feature -- Access
feed_from_string (a_content: READABLE_STRING_8): detachable FEED
-- Feed object from `a_content' string, if a parser is able to parse.it.
local
p: XML_STANDARD_PARSER
cb_tree: XML_CALLBACKS_FILTER_DOCUMENT
xdoc: XML_DOCUMENT
do
create p.make
create cb_tree.make_null
p.set_callbacks (cb_tree)
p.parse_from_string_8 (a_content)
if p.is_correct then
xdoc := cb_tree.document
Result := feed (xdoc)
end
end
feed (xdoc: XML_DOCUMENT): like feed_from_string
-- Feed from `xdoc' XML document.
do
across
parsers as ic
until
Result /= Void
loop
if ic.item.is_detected (xdoc) then
Result := ic.item.feed (xdoc)
end
end
end
end

View File

@@ -0,0 +1,62 @@
note
description: "[
Interface common to any FEED parser.
Usage:
create parser
if attached parser.feed_from_string (l_feed_content) as l_feed then
...
]"
date: "$Date$"
revision: "$Revision$"
deferred class
FEED_PARSER
inherit
FEED_PARSER_UTILITIES
feature -- Access
name: STRING
-- Associated name.
deferred
ensure
not_blanc: not Result.is_whitespace
end
is_detected (xdoc: XML_DOCUMENT): BOOLEAN
-- Is `xdoc' an feed representation or Current supported format?
deferred
end
feed (xdoc: XML_DOCUMENT): detachable FEED
-- Feed from `xdoc' XML document.
require
is_detected: is_detected (xdoc)
deferred
end
feature -- Basic operations
feed_from_string (a_content: READABLE_STRING_8): like feed
-- Feed from `a_content' document.
local
p: XML_STANDARD_PARSER
cb_tree: XML_CALLBACKS_FILTER_DOCUMENT
xdoc: XML_DOCUMENT
do
create p.make
create cb_tree.make_null
p.set_callbacks (cb_tree)
p.parse_from_string_8 (a_content)
if p.is_correct then
xdoc := cb_tree.document
if is_detected (xdoc) then
Result := feed (xdoc)
end
end
end
end

View File

@@ -0,0 +1,139 @@
note
description: "FEED interface, could be RSS, ATOM, ..."
date: "$Date$"
revision: "$Revision$"
class
FEED
inherit
FEED_HELPERS
ITERABLE [FEED_ITEM]
create
make
feature {NONE} -- Initialization
make (a_title: READABLE_STRING_GENERAL)
do
create title.make_from_string_general (a_title)
create items.make (1)
create links.make (1)
end
feature -- Access
title: IMMUTABLE_STRING_32
-- Title of the feed/channel.
description: detachable IMMUTABLE_STRING_32
-- Associated description/subtitle.
description_content_type: detachable READABLE_STRING_8
-- Optional content type for `description'.
-- By default, this should be text/plain.
id: detachable IMMUTABLE_STRING_32
-- Id associated with Current feed if any.
date: detachable DATE_TIME
-- Build date.
links: STRING_TABLE [FEED_LINK]
-- Url indexed by relation
items: ARRAYED_LIST [FEED_ITEM]
-- List of feed items.
feature -- Access
new_cursor: ITERATION_CURSOR [FEED_ITEM]
-- <Precursor>
do
Result := items.new_cursor
end
feature -- Element change
set_description (a_description: detachable READABLE_STRING_GENERAL; a_description_content_type: like description_content_type)
-- Set `description' with `a_description' and optional content type `text:$a_description_content_type'.
do
if a_description = Void then
description := Void
description_content_type := Void
else
create description.make_from_string_general (a_description)
description_content_type := a_description_content_type
end
end
set_id (a_id: detachable READABLE_STRING_GENERAL)
do
if a_id = Void then
id := Void
else
create id.make_from_string_general (a_id)
end
end
set_updated_date_with_text (a_date_text: detachable READABLE_STRING_32)
-- Set `date' from date string representation `a_date_text'.
do
if a_date_text = Void then
date := Void
else
date := date_time (a_date_text)
end
end
extend (a_item: FEED_ITEM)
-- Add item `a_item' to feed `items'.
do
items.force (a_item)
end
extended alias "+" (a_feed: FEED): FEED
-- New feed object made from Current merged with a_feed.
local
l_title: STRING_32
do
create l_title.make (title.count + a_feed.title.count)
l_title.append_character ('(')
l_title.append (title)
l_title.append_character (')')
l_title.append_character ('+')
l_title.append_character ('(')
l_title.append (a_feed.title)
l_title.append_character (')')
create Result.make (l_title)
Result.items.append (items)
across
a_feed.items as ic
loop
-- FIXME jfiat [2015/10/07] : check there is no duplication! (same id, or link, ...)
Result.extend (ic.item)
end
Result.sort
end
sort
-- Sort `items', (recent first).
local
s: QUICK_SORTER [FEED_ITEM]
comp: COMPARABLE_COMPARATOR [FEED_ITEM]
do
create comp
create s.make (comp)
s.reverse_sort (items)
end
feature -- Visitor
accept (vis: FEED_VISITOR)
do
vis.visit_feed (Current)
end
end

View File

@@ -0,0 +1,48 @@
note
description: "[
Author of feed or feed entry.
- name and email information.
]"
date: "$Date$"
revision: "$Revision$"
class
FEED_AUTHOR
create
make
feature {NONE} -- Initialization
make (a_name: READABLE_STRING_GENERAL)
do
create name.make_from_string_general (a_name)
end
feature -- Access
name: IMMUTABLE_STRING_32
email: detachable READABLE_STRING_8
feature -- Element change
set_email (a_email: detachable READABLE_STRING_GENERAL)
do
if a_email = Void then
email := Void
elseif a_email.is_valid_as_string_8 then
email := a_email.as_string_8
else
email := Void
end
end
feature -- Visitor
accept (vis: FEED_VISITOR)
do
vis.visit_author (Current)
end
end

View File

@@ -0,0 +1,193 @@
note
description: "[
A feed contains a list of items.
This FEED_ITEM interface provides
- title, description, content, id, date, ...
- could be compared with other item to sort by date+title.
]"
date: "$Date$"
revision: "$Revision$"
class
FEED_ITEM
inherit
FEED_HELPERS
undefine
is_equal
end
COMPARABLE
create
make
feature {NONE} -- Initialization
make (a_title: READABLE_STRING_GENERAL)
do
create title.make_from_string_general (a_title)
create links.make (1)
end
feature -- Access
title: IMMUTABLE_STRING_32
-- Title of associated feed item.
description: detachable IMMUTABLE_STRING_32
-- Optional description (or summary).
content: detachable IMMUTABLE_STRING_32
-- Content of Current feed item.
content_type: detachable READABLE_STRING_8
-- Optional content type for `content'.
-- By default, this should be text/html.
content_type_or_default (dft: READABLE_STRING_8): READABLE_STRING_8
-- Associated content type, and if none, return given value `dft'.
do
if attached content_type as l_type then
Result := l_type
else
Result := dft
end
end
id: detachable IMMUTABLE_STRING_32
-- Identifier of current feed item, if any/
date: detachable DATE_TIME
-- Publishing date.
link: detachable FEED_LINK
-- Main link for the entry, if any.
do
if attached links as l_links then
Result := l_links.item ("")
across
l_links as ic
until
Result /= Void
loop
Result := ic.item
end
end
end
links: STRING_TABLE [FEED_LINK]
-- Url indexed by relation
categories: detachable LIST [READABLE_STRING_32]
-- Categories
author: detachable FEED_AUTHOR
-- Author information.
feature -- Status report
has_category (cat: READABLE_STRING_GENERAL): BOOLEAN
-- Has category `cat'?
--| note: case insensitive.
do
if attached categories as cats then
Result := across cats as ic some cat.is_case_insensitive_equal (ic.item) end
end
end
feature -- Comparison
is_less alias "<" (other: like Current): BOOLEAN
-- Is current object less than `other'?
local
d1,d2: like date
do
d1 := date
d2 := other.date
if d1 = Void and d2 = Void then
Result := title < other.title
elseif d1 = Void then
Result := True
elseif d2 = Void then
Result := False
else
if d1 ~ d2 then
Result := title < other.title
else
Result := d1 < d2
end
end
end
feature -- Element change
set_id (a_id: detachable READABLE_STRING_GENERAL)
do
if a_id = Void then
id := Void
else
create id.make_from_string_general (a_id)
end
end
set_description (a_description: detachable READABLE_STRING_GENERAL)
do
if a_description = Void then
description := Void
else
create description.make_from_string_general (a_description)
end
end
set_content (a_content: detachable READABLE_STRING_GENERAL; a_type: detachable READABLE_STRING_GENERAL)
do
if a_content = Void then
content := Void
content_type := Void
else
create content.make_from_string_general (a_content)
if a_type = Void then
content_type := Void
else
content_type := a_type.as_string_8
end
end
end
set_updated_date_with_text (a_date_text: detachable READABLE_STRING_32)
do
if a_date_text = Void then
date := Void
else
date := date_time (a_date_text)
end
end
set_author (a_author: detachable FEED_AUTHOR)
do
author := a_author
end
set_category (cat: READABLE_STRING_GENERAL)
local
cats: like categories
do
cats := categories
if cats = Void then
create {ARRAYED_LIST [READABLE_STRING_32]} cats.make (1)
categories := cats
end
cats.force (cat.as_string_32)
ensure
cat_set: has_category (cat)
end
feature -- Visitor
accept (vis: FEED_VISITOR)
do
vis.visit_item (Current)
end
end

View File

@@ -0,0 +1,58 @@
note
description: "Link mentioned in feed and feed entry."
date: "$Date$"
revision: "$Revision$"
class
FEED_LINK
create
make
feature {NONE} -- Initialization
make (a_href: READABLE_STRING_8)
do
href := a_href
set_relation (Void)
end
feature -- Access
href: READABLE_STRING_8
-- Location of Current link.
relation: READABLE_STRING_32
-- Relation associated with Current link.
type: detachable READABLE_STRING_8
-- Optional type of link.
feature -- Element change
set_relation (rel: detachable READABLE_STRING_GENERAL)
do
if rel = Void then
relation := ""
else
relation := rel.as_string_8
end
end
set_type (a_type: detachable READABLE_STRING_GENERAL)
do
if a_type = Void then
type := Void
else
type := a_type.as_string_8
end
end
feature -- Visitor
accept (vis: FEED_VISITOR)
do
vis.visit_link (Current)
end
end

View File

@@ -0,0 +1,126 @@
note
description: "Convert a FEED into an RSS 2.0 content."
date: "$Date$"
revision: "$Revision$"
class
RSS_2_FEED_GENERATOR
inherit
FEED_VISITOR
FEED_GENERATOR
rename
process_feed as visit_feed
end
create
make
feature -- Visitor
visit_feed (a_feed: FEED)
do
buffer.append ("[
<?xml version="1.0" encoding="UTF-8"?>
<rss
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
version="2.0">
<channel>
]")
buffer.append_character ('%N')
indent
indent
append_content_tag_to ("title", Void, a_feed.title, buffer)
append_content_tag_to ("description", Void, a_feed.description, buffer)
across
a_feed.links as tb
loop
tb.item.accept (Current)
end
if attached a_feed.date as dt then
append_content_tag_to ("lastBuildDate", Void, date_to_string (dt), buffer)
end
across
a_feed.items as ic
loop
ic.item.accept (Current)
end
exdent
exdent
buffer.append ("[
</channel>
</rss>
]")
end
visit_item (a_item: FEED_ITEM)
do
buffer.append (indentation)
buffer.append ("<item>%N")
indent
append_content_tag_to ("title", Void, a_item.title, buffer)
if attached a_item.date as dt then
append_content_tag_to ("pubDate", Void, date_to_string (dt), buffer)
end
across
a_item.links as tb
loop
tb.item.accept (Current)
end
if attached a_item.author as u then
u.accept (Current)
end
if attached a_item.categories as cats then
across
cats as ic
loop
append_content_tag_to ("category", Void, ic.item, buffer)
end
end
append_content_tag_to ("guid", Void, a_item.id, buffer)
append_content_tag_to ("description", Void, a_item.description, buffer)
append_cdata_content_tag_to ("content:encoded", Void, a_item.content, buffer)
exdent
buffer.append (indentation)
buffer.append ("</item>%N")
end
visit_link (a_link: FEED_LINK)
local
attr: detachable ARRAYED_LIST [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_32]]
tu: TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_32]
do
create attr.make (2)
if attached a_link.relation as rel and then not rel.is_whitespace then
tu := ["rel", rel]
attr.force (tu)
end
if attached a_link.type as t and then not t.is_whitespace then
tu := ["type", t.as_string_32]
attr.force (tu)
end
if attr.is_empty then
attr := Void
end
append_content_tag_to ("link", attr, a_link.href, buffer)
end
visit_author (a_author: FEED_AUTHOR)
do
append_content_tag_to ("dc:creator", Void, a_author.name, buffer)
end
feature {NONE} -- Helpers
date_to_string (dt: DATE_TIME): STRING
local
htdate: HTTP_DATE
do
create htdate.make_from_date_time (dt)
Result := htdate.rfc850_string
end
end

View File

@@ -0,0 +1,125 @@
note
description: "[
RSS 2.0 Parser.
Warning: the implementation may not support the full RSS 2.0 specification.
]"
date: "$Date$"
revision: "$Revision$"
EIS: "name=RSS at wikipedia", "protocol=URI", "src=https://en.wikipedia.org/wiki/RSS"
EIS: "name=RDF Site Summary (RSS) 1.0", "protocol=URI", "src=http://purl.org/rss/1.0/spec"
class
RSS_2_FEED_PARSER
inherit
FEED_PARSER
feature -- Access
name: STRING = "rss2"
-- Associated name.
is_detected (xdoc: XML_DOCUMENT): BOOLEAN
-- Is `xdoc' an ATOM feed representation?
do
if attached {XML_ELEMENT} xdoc.element_by_name ("rss") as x_rss then
if attached xml_attribute_text (x_rss, "version") as l_version and then
l_version.starts_with ("2.")
then
Result := True
else
-- Let's default to RSS 2.0 for now.
Result := True
end
end
end
feed (xdoc: XML_DOCUMENT): detachable FEED
-- Feed from `xdoc' XML RSS 2.0 document.
local
lnk: FEED_LINK
x_item, x_content, x_author: detachable XML_ELEMENT
e: FEED_ITEM
l_author: FEED_AUTHOR
do
if attached xdoc.element_by_name ("rss") as x_rss then
if
attached xml_attribute_text (x_rss, "version") as l_version and then
l_version.starts_with ("2.")
then
if attached x_rss.element_by_name ("channel") as x_channel then
if attached xml_element_text (x_channel, "title") as x_title then
create Result.make (x_title)
Result.set_description (xml_element_text (x_channel, "description"), "xhtml")
Result.set_updated_date_with_text (xml_element_text (x_channel, "lastBuildDate"))
if attached links_from_xml (x_channel, "link") as l_links then
across
l_links as link_ic
loop
lnk := link_ic.item
Result.links.force (lnk, lnk.relation)
end
end
if attached x_channel.elements_by_name ("item") as x_items then
across
x_items as ic
loop
x_item := ic.item
if attached xml_element_text (x_item, "title") as e_title then
create e.make (e_title)
e.set_description (xml_element_text (x_item, "description"))
e.set_updated_date_with_text (xml_element_text (x_item, "pubDate"))
e.set_id (xml_element_text (x_item, "guid"))
x_author := x_item.element_by_name ("creator")
if x_author = Void then
x_author := element_by_prefixed_name (x_item, "dc" , "creator")
end
if
x_author /= Void and then
attached x_author.text as l_author_name
then
create l_author.make (l_author_name)
e.set_author (l_author)
end
if attached links_from_xml (x_item, "link") as l_links then
across
l_links as link_ic
loop
lnk := link_ic.item
e.links.force (lnk, lnk.relation)
end
end
if attached x_item.elements_by_name ("category") as x_categories then
across
x_categories as cats
loop
if attached cats.item.text as cat then
e.set_category (cat)
end
end
end
x_content := x_item.element_by_name ("content")
if x_content = Void then
x_content := element_by_prefixed_name (x_item, "content" , "encoded")
if x_content /= Void then
e.set_content (x_content.text, Void)
end
else
e.set_content (xml_element_code (x_content), Void)
end
Result.extend (e)
end
end
end
end
end
end
end
end
end

View File

@@ -0,0 +1,119 @@
note
description: "Common ancestor for feed generator."
date: "$Date$"
revision: "$Revision$"
deferred class
FEED_GENERATOR
inherit
XML_UTILITIES
feature {NONE} -- Initialization
make (a_buffer: STRING_8)
do
buffer := a_buffer
create indentation.make_empty
end
feature -- Access
buffer: STRING_8
-- Output of feed conversion.
feature -- Conversion
process_feed (a_feed: FEED)
-- Convert `a_feed' into string representation in `buffer'.
deferred
end
feature {NONE} -- Helpers
indent
do
indentation.append ("%T")
end
exdent
require
has_indentation: indentation.count > 0
do
indentation.remove_tail (1)
end
indentation: STRING
append_content_tag_to (a_tagname: READABLE_STRING_8; a_attr: detachable ITERABLE [TUPLE [name: READABLE_STRING_8; value: detachable READABLE_STRING_GENERAL]]; a_content: detachable READABLE_STRING_GENERAL; a_output: STRING)
do
if a_content /= Void or a_attr /= Void then
a_output.append (indentation)
a_output.append ("<")
a_output.append (a_tagname)
if a_attr /= Void then
across
a_attr as ic
loop
if attached ic.item.value as l_att_value then
a_output.append_character (' ')
a_output.append (ic.item.name)
a_output.append_character ('=')
a_output.append_character ('%"')
a_output.append (escaped_unicode_xml (l_att_value.as_string_32))
a_output.append_character ('%"')
end
end
end
if a_content = Void then
a_output.append ("/>")
else
a_output.append (">")
a_output.append (escaped_unicode_xml (a_content.as_string_32))
a_output.append ("</" + a_tagname + ">%N")
end
end
end
append_cdata_content_tag_to (a_tagname: READABLE_STRING_8; a_attr: detachable ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_32]]; a_content: detachable READABLE_STRING_32; a_output: STRING)
do
if a_content /= Void then
a_output.append (indentation)
a_output.append ("<")
a_output.append (a_tagname)
if a_attr /= Void then
across
a_attr as ic
loop
a_output.append_character (' ')
a_output.append (ic.item.name)
a_output.append_character ('=')
a_output.append_character ('%"')
a_output.append (escaped_unicode_xml (ic.item.value))
a_output.append_character ('%"')
end
end
a_output.append (">")
a_output.append (to_cdata_element (a_content))
a_output.append ("</" + a_tagname + ">%N")
end
end
to_cdata_element (a_value: READABLE_STRING_GENERAL): STRING
local
cdata: XML_CHARACTER_DATA
xdoc: XML_DOCUMENT
pprinter: XML_NODE_PRINTER
l_output: XML_STRING_8_OUTPUT_STREAM
do
create xdoc.make
create cdata.make (xdoc.root_element, a_value.as_string_32)
create pprinter.make
create Result.make (cdata.content_count)
create l_output.make (Result)
pprinter.set_output (l_output)
pprinter.process_character_data (cdata)
end
end

View File

@@ -0,0 +1,86 @@
note
description: "Helpers routine for feed library."
date: "$Date$"
revision: "$Revision$"
class
FEED_HELPERS
feature -- Helpers
date_time (a_date_string: READABLE_STRING_32): DATE_TIME
-- "2015-08-14T10:34:13.493740Z"
-- "Sat, 07 Sep 2002 00:00:01 GMT"
local
i,j: INTEGER
s: READABLE_STRING_GENERAL
y,m,d,h,min: INTEGER
sec: REAL_64
htdate: HTTP_DATE
str: STRING_32
do
if a_date_string.count > 0 and then a_date_string.item (1).is_digit then
i := a_date_string.index_of ('-', 1)
if i > 0 then
s := a_date_string.substring (1, i - 1)
y := s.to_integer_32 -- Year
j := i + 1
i := a_date_string.index_of ('-', j)
if i > 0 then
s := a_date_string.substring (j, i - 1)
m := s.to_integer_32 -- Month
j := i + 1
i := a_date_string.index_of ('T', j)
if i = 0 then
i := a_date_string.index_of (' ', j)
end
if i = 0 then
i := a_date_string.count + 1
end
if i > 0 then
s := a_date_string.substring (j, i - 1)
if s.is_integer then
d := s.to_integer_32 -- Day
j := i + 1
i := a_date_string.index_of (':', j)
if i > 0 then
s := a_date_string.substring (j, i - 1)
h := s.to_integer
j := i + 1
i := a_date_string.index_of (':', j)
if i > 0 then
s := a_date_string.substring (j, i - 1)
min := s.to_integer
j := i + 1
i := a_date_string.index_of ('Z', j)
if i = 0 then
i := a_date_string.count + 1
end
s := a_date_string.substring (j, i - 1)
sec := s.to_double
end
end
end
end
end
end
create Result.make (y,m,d,h,m,0)
Result.fine_second_add (sec)
else
i := a_date_string.index_of ('+', 1)
if i > 0 then
str := a_date_string.substring (1, i - 1)
str.append (" GMT")
create htdate.make_from_string (str)
Result := htdate.date_time
if a_date_string.substring (i + 1, a_date_string.count).is_case_insensitive_equal ("0000") then
end
else
create htdate.make_from_string (a_date_string)
Result := htdate.date_time
end
end
end
end

View File

@@ -0,0 +1,83 @@
note
description: "Helpers routine for feed xml parsers."
date: "$Date$"
revision: "$Revision$"
deferred class
FEED_PARSER_UTILITIES
feature -- Access
xml_element_text (a_parent: XML_ELEMENT; a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
do
if attached a_parent.element_by_name (a_name) as elt then
if attached elt.text as t then
t.left_adjust
t.right_adjust
Result := t
end
end
end
xml_attribute_text (a_elt: XML_ELEMENT; a_att_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
do
if attached a_elt.attribute_by_name (a_att_name) as att then
Result := att.value
end
end
xml_element_code (elt: XML_ELEMENT): STRING_32
local
xprinter: XML_NODE_PRINTER
do
create xprinter.make
create Result.make_empty
xprinter.set_output (create {XML_STRING_32_OUTPUT_STREAM}.make (Result))
xprinter.process_element (elt)
end
links_from_xml (elt: XML_ELEMENT; a_link_elt_name: READABLE_STRING_GENERAL): detachable ARRAYED_LIST [FEED_LINK]
local
x_link: XML_ELEMENT
lnk: FEED_LINK
do
if attached elt.elements_by_name (a_link_elt_name) as x_links then
create Result.make (0)
across
x_links as ic
loop
x_link := ic.item
if attached xml_attribute_text (x_link, "href") as l_href and then
l_href.is_valid_as_string_8
then
create lnk.make (l_href.as_string_8)
lnk.set_relation (xml_attribute_text (x_link, "rel"))
lnk.set_type (xml_attribute_text (x_link, "type"))
Result.force (lnk)
elseif attached x_link.text as l_url and then not l_url.is_whitespace then
create lnk.make (l_url)
Result.force (lnk)
end
end
end
end
element_by_prefixed_name (elt: XML_ELEMENT; a_ns_prefix: READABLE_STRING_GENERAL; a_name: READABLE_STRING_GENERAL): detachable XML_ELEMENT
do
across
elt as ic
until
Result /= Void
loop
if attached {XML_ELEMENT} ic.item as x_item then
if
attached x_item.ns_prefix as l_ns_prefix and then a_ns_prefix.same_string (l_ns_prefix) and then
a_name.same_string (x_item.name)
then
Result := x_item
end
end
end
end
end

View File

@@ -0,0 +1,200 @@
note
description: "[
Convert a FEED to STRING_32 representation.
Mostly for debug output!
]"
date: "$Date$"
revision: "$Revision$"
class
FEED_TO_STRING_32_DEBUG_VISITOR
inherit
FEED_VISITOR
create
make
feature {NONE} -- Initialization
make (a_buffer: STRING_32)
do
buffer := a_buffer
create indentation.make_empty
end
buffer: STRING_32
feature -- Visitor
visit_feed (a_feed: FEED)
do
if attached a_feed.id as l_id then
append_text ("#")
append (l_id)
append_new_line
end
if attached a_feed.date as dt then
append_text ("date:")
append (dt.out)
append_new_line
end
append_text (a_feed.title)
append_new_line
indent
if attached a_feed.description as l_desc then
append_text (l_desc)
append_new_line
end
across
a_feed.links as ic
loop
ic.item.accept (Current)
append_new_line
end
append_new_line
across
a_feed.items as ic
loop
exdent
append_text (create {STRING_32}.make_filled ('-', 40))
append_new_line
indent
ic.item.accept (Current)
append_new_line
end
end
visit_item (a_entry: FEED_ITEM)
do
if attached a_entry.id as l_id then
append_text ("#")
append (l_id)
append_new_line
end
if attached a_entry.date as dt then
append_text ("date:")
append (dt.out)
append_new_line
end
append_text (a_entry.title)
append_new_line
indent
if attached a_entry.author as l_author then
l_author.accept (Current)
append_new_line
end
if attached a_entry.categories as cats then
append_text ("Categories: ")
from
cats.start
until
cats.after
loop
if not cats.isfirst then
append (", ")
end
append (cats.item)
cats.forth
end
append_new_line
end
if attached a_entry.description as l_summary then
append_text (l_summary)
append_new_line
end
across
a_entry.links as ic
loop
ic.item.accept (Current)
append_new_line
end
if attached a_entry.content as l_content then
append_text (l_content)
append_new_line
end
exdent
end
visit_link (a_link: FEED_LINK)
local
s: STRING_32
do
create s.make_empty
s.append_string_general ("@")
s.append_string (a_link.relation)
s.append_string (" -> ")
s.append_string (a_link.href)
append_text (s)
end
visit_author (a_author: FEED_AUTHOR)
local
s: STRING_32
do
create s.make_empty
s.append_string_general ("by ")
s.append_string (a_author.name)
if attached a_author.email as l_email then
s.append_character (' ')
s.append_character ('(')
s.append_string_general (l_email)
s.append_character (')')
end
append_text (s)
end
feature -- Helper
indentation: STRING_32
indent
do
indentation.append (" ")
end
exdent
do
indentation.remove_tail (2)
end
append_new_line
do
append ("%N")
end
append_text (s: READABLE_STRING_GENERAL)
local
lst: LIST [READABLE_STRING_GENERAL]
do
if indentation.is_empty then
append (s)
else
lst := s.split ('%N')
from
lst.start
until
lst.after
loop
append (indentation)
append (lst.item)
if not lst.islast then
append ("%N")
end
lst.forth
end
end
end
append (s: READABLE_STRING_GENERAL)
do
buffer.append_string_general (s)
end
end

View File

@@ -0,0 +1,27 @@
note
description: "Interface to visit Feed objects."
date: "$Date$"
revision: "$Revision$"
deferred class
FEED_VISITOR
feature -- Visit
visit_feed (a_feed: FEED)
deferred
end
visit_link (a_link: FEED_LINK)
deferred
end
visit_item (a_item: FEED_ITEM)
deferred
end
visit_author (a_author: FEED_AUTHOR)
deferred
end
end

View File

@@ -0,0 +1,91 @@
note
description: "Summary description for {APPLICATION}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
APPLICATION
create
make
feature -- Initialization
make
-- New test routine
do
test_file ("data_rss_1_0.rss")
test_web ("https://bertrandmeyer.com/feed/")
end
test_file (fn: READABLE_STRING_GENERAL)
local
t: STRING
f: PLAIN_TEXT_FILE
do
create f.make_with_name (fn)
f.open_read
create t.make_empty
from
f.read_stream_thread_aware (1_024)
until
f.last_string.count < 1024
loop
t.append (f.last_string)
f.read_stream_thread_aware (1_024)
end
t.append (f.last_string)
f.close
test_feed (t)
end
test_feed (t: READABLE_STRING_8)
local
feed_parser: FEED_DEFAULT_PARSERS
vis: FEED_TO_STRING_32_DEBUG_VISITOR
gen: RSS_2_FEED_GENERATOR
atom_gen: ATOM_FEED_GENERATOR
s: STRING_32
s8: STRING_8
pp: XML_PRETTY_PRINT_FILTER
do
create feed_parser
if attached feed_parser.feed_from_string (t) as l_feed then
create s.make_empty
create vis.make (s)
l_feed.accept (vis)
print (s)
create s8.make_empty
create gen.make (s8)
l_feed.accept (gen)
print (s8)
create s8.make_empty
create atom_gen.make (s8)
l_feed.accept (atom_gen)
print (s8)
end
end
test_web (a_url: READABLE_STRING_8)
local
cl: LIBCURL_HTTP_CLIENT
sess: HTTP_CLIENT_SESSION
do
create cl.make
sess := cl.new_session (a_url)
sess.set_is_insecure (True)
if attached sess.get ("", Void) as resp then
if
not resp.error_occurred and then
attached resp.body as l_feed
then
test_feed (l_feed)
end
end
end
end

View File

@@ -0,0 +1,74 @@
note
description: "[
Eiffel tests that can be executed by testing tool.
]"
author: "EiffelStudio test wizard"
date: "$Date$"
revision: "$Revision$"
testing: "type/manual"
class
ATOM_TEST_SET
inherit
EQA_TEST_SET
feature -- Test routines
test_atom
-- New test routine
local
feed_parser: FEED_DEFAULT_PARSERS
vis: FEED_TO_STRING_32_DEBUG_VISITOR
s: STRING_32
do
create feed_parser
if attached feed_parser.feed_from_string (atom_string_1) as l_feed then
create s.make_empty
create vis.make (s)
l_feed.accept (vis)
print (s)
assert ("not_implemented", False)
end
assert ("not_implemented", False)
end
feature {NONE} -- Data
atom_string_1: STRING = "[
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Example Feed</title>
<subtitle>A subtitle.</subtitle>
<link href="http://example.org/feed/" rel="self" />
<link href="http://example.org/" />
<id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>
<updated>2003-12-13T18:30:02Z</updated>
<entry>
<title>Atom-Powered Robots Run Amok</title>
<link href="http://example.org/2003/12/13/atom03" />
<link rel="alternate" type="text/html" href="http://example.org/2003/12/13/atom03.html"/>
<link rel="edit" href="http://example.org/2003/12/13/atom03/edit"/>
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
<updated>2003-12-13T18:30:02Z</updated>
<summary>Some text.</summary>
<content type="xhtml">
<div xmlns="http://www.w3.org/1999/xhtml">
<p>This is the entry content.</p>
</div>
</content>
<author>
<name>John Doe</name>
<email>johndoe@example.com</email>
</author>
</entry>
</feed>
]"
end

View File

@@ -0,0 +1,60 @@
note
description: "Summary description for {RSS_TEST_SET}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
RSS_TEST_SET
inherit
EQA_TEST_SET
feature -- Test routines
test_rss_2
-- New test routine
local
feed_parser: FEED_DEFAULT_PARSERS
vis: FEED_TO_STRING_32_DEBUG_VISITOR
s: STRING_32
do
create feed_parser
if attached feed_parser.feed_from_string (rss_2_string_1) as l_feed then
create s.make_empty
create vis.make (s)
l_feed.accept (vis)
print (s)
assert ("not_implemented", False)
end
assert ("not_implemented", False)
end
feature {NONE} -- Data
rss_2_string_1: STRING = "[
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>Mon site</title>
<description>Ceci est un exemple de flux RSS 2.0</description>
<lastBuildDate>Sat, 07 Sep 2002 00:00:01 GMT</lastBuildDate>
<link>http://www.example.org</link>
<item>
<title>Post N1</title>
<description>This is my first post</description>
<pubDate>Sat, 07 Sep 2002 00:00:01 GMT</pubDate>
<link>http://www.example.org/actu1</link>
</item>
<item>
<title>Post N2</title>
<description>This is my second post</description>
<pubDate>Sat, 07 Sep 2002 00:00:01 GMT</pubDate>
<link>http://www.example.org/actu2</link>
</item>
</channel>
</rss>
]"
end

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-14-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-14-0 http://www.eiffel.com/developers/xml/configuration-1-14-0.xsd" name="tests" uuid="C68BD5DC-F756-484E-A9FE-F2D1FD432B2A">
<target name="tests">
<root class="APPLICATION" feature="make"/>
<setting name="console_application" value="false"/>
<setting name="concurrency" value="none"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="feed" location="..\feed-safe.ecf" readonly="false"/>
<library name="http_client" location="$ISE_LIBRARY\contrib\library\network\http_client\http_client-safe.ecf"/>
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
<library name="xml_parser" location="$ISE_LIBRARY\library\text\parser\xml\parser\xml_parser-safe.ecf"/>
<tests name="src" location=".\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-14-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-14-0 http://www.eiffel.com/developers/xml/configuration-1-14-0.xsd" name="tests" uuid="C68BD5DC-F756-484E-A9FE-F2D1FD432B2A">
<target name="tests">
<root class="ANY" feature="default_create"/>
<setting name="console_application" value="false"/>
<setting name="concurrency" value="none"/>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="feed" location="..\feed.ecf"/>
<library name="testing" location="$ISE_LIBRARY\library\testing\testing.ecf"/>
<tests name="src" location=".\" recursive="true"/>
</target>
</system>

View File

@@ -45,7 +45,8 @@
<library name="rss" location="..\draft\library\protocol\syndication\rss\rss-safe.ecf" readonly="false"/>
<library name="upload_image" location="..\examples\upload_image\upload_image-safe.ecf" readonly="false"/>
<library name="uri_template" location="..\library\text\parser\uri_template\uri_template-safe.ecf" readonly="false"/>
<library name="wizard" location="..\tools\estudio_wizard\ewf_ise_wizard-safe.ecf" readonly="false"/>
<library name="wizard" location="..\tools\estudio_wizard\wizard.ecf" readonly="false"/>
<library name="console_wizard" location="..\tools\estudio_wizard\console_wizard.ecf" readonly="false"/>
<library name="wsf" location="..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
<library name="wsf_all" location="..\library\server\wsf\connector\all-safe.ecf" readonly="false"/>
<library name="wsf_cgi" location="..\library\server\wsf\connector\cgi-safe.ecf" readonly="false"/>

View File

@@ -40,7 +40,8 @@
<library name="restbucks" location="..\examples\restbucksCRUD\restbucks-safe.ecf" readonly="false"/>
<library name="upload_image" location="..\examples\upload_image\upload_image-safe.ecf" readonly="false"/>
<library name="uri_template" location="..\library\text\parser\uri_template\uri_template-safe.ecf" readonly="false"/>
<library name="wizard" location="..\tools\estudio_wizard\ewf_ise_wizard-safe.ecf" readonly="false"/>
<library name="wizard" location="..\tools\estudio_wizard\wizard.ecf" readonly="false"/>
<library name="console_wizard" location="..\tools\estudio_wizard\console_wizard.ecf" readonly="false"/>
<library name="wsf" location="..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
<library name="wsf_all" location="..\library\server\wsf\connector\all-safe.ecf" readonly="false"/>
<library name="wsf_cgi" location="..\library\server\wsf\connector\cgi-safe.ecf" readonly="false"/>
@@ -63,4 +64,9 @@
<root all_classes="true"/>
<setting name="platform" value="unix"/>
</target>
<target name="all_stable_with_ssl" extends="all_stable">
<description>Compiling with ssl enabled</description>
<root all_classes="true"/>
<variable name="httpd_ssl_enabled" value="true"/>
</target>
</system>

View File

@@ -38,7 +38,7 @@ feature {NONE} -- Initialization
feature -- UI change
set_title (a_title: READABLE_STRING_GENERAL)
set_title (a_title: separate READABLE_STRING_GENERAL)
deferred
end

View File

@@ -89,15 +89,17 @@ echo Install library: http
echo Install library: content_negotiation
%COPYCMD% %TMP_DIR%\library\network\protocol\content_negotiation %TMP_CONTRIB_DIR%\library\network\protocol\content_negotiation
echo Install library: http_authorization
%SAFE_MD% %TMP_CONTRIB_DIR%\library\network\authentication
%COPYCMD% %TMP_DIR%\library\server\authentication\http_authorization %TMP_CONTRIB_DIR%\library\network\authentication\http_authorization
%SAFE_MD% %TMP_CONTRIB_DIR%\library\web\authentication
%COPYCMD% %TMP_DIR%\library\server\authentication\http_authorization %TMP_CONTRIB_DIR%\library\web\authentication\http_authorization
echo Install library: openid
%SAFE_MD% %TMP_CONTRIB_DIR%\library\security
%COPYCMD% %TMP_DIR%\library\security\openid %TMP_CONTRIB_DIR%\library\security\openid
%SAFE_MD% %TMP_CONTRIB_DIR%\library\web\authentication
%COPYCMD% %TMP_DIR%\library\security\openid %TMP_CONTRIB_DIR%\library\web\authentication\openid
echo Install library: uri_template
%COPYCMD% %TMP_DIR%\library\text\parser\uri_template %TMP_CONTRIB_DIR%\library\text\parser\uri_template
echo Install library: feed
%COPYCMD% %TMP_DIR%\library\text\parser\feed %TMP_CONTRIB_DIR%\library\text\parser\feed
echo Install library: notification_email
%SAFE_MD% %TMP_CONTRIB_DIR%\library\runtime

View File

@@ -60,11 +60,13 @@ echo Uninstall library: http
echo Uninstall library: content_negotiation
%RDCMD% %TMP_CONTRIB_DIR%\library\network\protocol\content_negotiation
echo Uninstall library: http_authorization
%RDCMD% %TMP_CONTRIB_DIR%\library\network\authentication\http_authorization
%RDCMD% %TMP_CONTRIB_DIR%\library\web\authentication\http_authorization
echo Uninstall library: security\openid
%RDCMD% %TMP_CONTRIB_DIR%\library\security\openid
%RDCMD% %TMP_CONTRIB_DIR%\library\web\authentication\openid
echo Uninstall library: uri_template
%RDCMD% %TMP_CONTRIB_DIR%\library\text\parser\uri_template
echo Uninstall library: feed
%RDCMD% %TMP_CONTRIB_DIR%\library\text\parser\feed
echo Uninstall library: runtime\process\notification_email
%RDCMD% %TMP_CONTRIB_DIR%\library\runtime\process\notification_email