Compare commits

..

47 Commits

Author SHA1 Message Date
b790c7fd21 cosmetic, cleaning. 2015-06-10 10:59:24 +02:00
9424b1e369 Merge branch 'master' into v1 2015-06-08 10:10:51 +02:00
64463df552 Fixed various compilation error or warning. 2015-06-05 12:17:53 +02:00
jvelilla
61f90bba38 Merge branch 'jvelilla-ewf_wsf_html5' 2015-05-29 15:38:30 -03:00
jvelilla
fac3dd3946 Merge branch 'ewf_wsf_html5' of https://github.com/jvelilla/EWF into jvelilla-ewf_wsf_html5 2015-05-29 15:38:08 -03:00
jvelilla
e1b583a2b3 Updated code based on comments 2015-05-28 10:07:40 -03:00
jvelilla
8c8dfdd4a3 Updated code based on review 2015-05-28 10:04:13 -03:00
jvelilla
857397e226 Updated code inherit from SHARED_HTML_ENCODER instead of creating new objects. 2015-05-28 09:39:14 -03:00
jvelilla
94340c1c01 Updated html5 classes based on review 2015-05-28 09:19:21 -03:00
8b60ab08e3 Added WSF_FILE_UTILITIES.new_file (p: PATH): detachable G
in order to provide non existing file, but not only for temporary files purpose.
2015-05-22 22:27:28 +02:00
jvelilla
28e51cc314 Initial import HTML5 support for attributes and input types.
Attributes
- Added support for new HTML5 attributes.
missing support for : form, list, and multiple attributes.

Input types: added the all the new input types.

Added test cases, still in progress.
2015-05-21 12:32:08 -03:00
jvelilla
a7c8d40b3e Moved EWF workbook from ewf_example to EWF main repository. 2015-05-18 11:06:04 -03:00
d4c0ff03b4 Added package.iron for nino library. 2015-05-12 19:04:36 +02:00
7fbfda3a66 Refactored wsf router dispatching implementation.
Now the path to take into account during dispatching is computed once
  in WSF_ROUTER.path_to_dispatch (req: WSF_REQUEST): READABLE_STRING_8
  And this function could be redefined in descendant of WSF_ROUTER.
2015-05-12 18:37:25 +02:00
9e467689df improved nino port number validation 2015-05-12 18:25:22 +02:00
dd5c89e31c Fixed compilation of SSL_TCP_STREAM_SOCKET with recent do_accept changes. 2015-05-07 10:44:38 +02:00
fffa763d05 Updated a few comments. 2015-05-06 22:37:55 +02:00
d015c065f6 Updated readme. 2015-05-06 22:18:27 +02:00
8ea443c115 Added abstraction WSF_ROUTED, and WSF_FILTERED.
Added under library/server/obsolete/v0 the previous non concurrent friendly version of EWF/WSF, for backward compatiblity.
Removed WSF_CALLBACK_SERVICE and WSF_TO_WGI_SERVICE which are not need with new EWF.
2015-05-06 22:17:37 +02:00
019393fdb1 Fixed typo. 2015-05-06 22:17:35 +02:00
da8028f8b3 Fixed a typo. 2015-05-06 22:17:33 +02:00
20ed000879 Added a few descriptions and comments. 2015-05-06 22:16:57 +02:00
jvelilla
24620b228c Added feature comments.
Added missing postconditions.
2015-05-06 22:16:10 +02:00
jvelilla
9c7e29b836 Added descriptions and comments 2015-05-06 22:16:08 +02:00
jvelilla
a0e9a41e21 Added descriptions and feature comments. 2015-05-06 22:16:07 +02:00
jvelilla
dd9aff03d3 Added features comments. 2015-05-06 22:16:05 +02:00
jvelilla
dc35925eb0 Added Missing Class and feature descriptions.
Removed author entry.
2015-05-06 22:16:03 +02:00
a1a620a9c3 Export request and response from WGI_EXECUTION to itself.
Added WSF_FILTERED_ROUTED_SKELETON_EXECUTION
2015-05-06 22:16:00 +02:00
d8ea9ba63c renamed keep_alive_requested as is_persistent_connection_requested. 2015-05-06 22:15:59 +02:00
c42af5b2de Following the spec, use "keep-alive" and "close" in lowercase for Connection header. 2015-05-06 22:15:57 +02:00
d9cbc72058 Better support for HTTP/1.0 and also related to persistent connection. 2015-05-06 22:15:56 +02:00
7e057b20b1 Improved support for HTTP/1.0 persistent connection. 2015-05-06 22:15:54 +02:00
3165c1e5c6 Enable support for persistent connections.
(test: works fine with curl -k , but weird behavior with ab -k ...)
2015-05-06 22:15:53 +02:00
89e26519e4 First step to improve a bit error handling related to socket disconnection.
Mainly in standalone connector for now.
2015-05-06 22:15:51 +02:00
9d20e85c03 Improved the simple_file example with image, and not found message.
Use standalone connector in SCOOP concurrency mode.
2015-05-06 22:15:50 +02:00
48cb99498c Cleaned simple example, and made the standalone target with SCOOP concurrency. 2015-05-06 22:15:48 +02:00
8246bc1444 Updated various indexing notes.
Removed a few obsolete classes.
Cosmetics
2015-05-06 22:15:46 +02:00
9e1083eba8 Added migration note. 2015-05-06 22:15:44 +02:00
4907bc3085 Migrated most of the example and library to new design. 2015-05-06 22:15:43 +02:00
7d2ce8a77f Implemented support for base url in httpd connector. 2015-05-06 22:15:38 +02:00
b4a9c92ffc Migrated simple, simple_file and upload_image example.
Adapted EWF accordingly.
2015-05-06 22:14:48 +02:00
bf0eb9a02d Added SCOOP support for WSF.
WSF_SERVICE is deeply changed, and addition of WSF_EXECUTION.
Todo: code cleaning, removing useless things.
2015-05-06 22:13:22 +02:00
ddf73077b3 Support for concurrencies: none, thread and SCOOP 2015-05-06 22:13:19 +02:00
3da80fce0d Finally SCOOP supported. 2015-05-06 22:13:17 +02:00
0970de5dc6 Experiment to avoid pseudo sequential execution 2015-05-06 22:13:15 +02:00
557b11f4e6 First attempt to use `{NETWORK_STREAM_SOCKET}.accept_to' 2015-05-06 22:13:13 +02:00
7f27a6c797 First steps to provide a concurrent compliant EWF connector. 2015-05-06 22:13:11 +02:00
349 changed files with 19090 additions and 3140 deletions

View File

@@ -1,38 +1,7 @@
History for Eiffel-Web-Framework
[2015-06-10]
* Updated EWF design to better support concurrency, including SCOOP via
the new standalone connector.
[2011-09-23] Jocelyn
* library "ewsgi":
- NEW simple autotest cases using Nino web server
-fixed issue with RAW_POST_DATA being added in form_data_parameters
instead of meta_variables ...
- Implemented WGI_VALUE for parameter's type (query_parameter,
form_data_parameter, item ...)
* Nino connector: added feature to shutdown the server from the WGI application
* NEW library "http_client": a new library to perform simple http requests
such as get, head, post, put, ... (currently implemented with Eiffel cURL)
* NEW library "http_authorization": added simple library to support
HTTP_AUTHORIZATION. For now only "Basic" auth type is supported ..
[2011-09-22] Javier
* NEW Example: added partial Restbuck example
[2011-09-21] Jocelyn
* Nino connector: fixed an issue with missing value for Content-Type and Content-Length
[2011-09-13] Jocelyn
* library "router": now using a generic design to allow customization of
request handler context class.
* NEW library "server/request/rest": first attempt to provide a library to
help building RESTful application (the interfaces are likely to change
soon) EXPERIMENTAL
[2011-09-09] Jocelyn
* library "uri-template": better support for {/vars} and {?vars}
[2011-09-07] Jocelyn
* library "router": now routing depends on uri (or uri template) and request methods
* Nino connector: Fixed issue where HTTP_ prefix were missing for header meta variable.
[2011-09-07] Jocelyn
* changelog: starting to write down changelogs file
[Previous ] Many significant changes in v0

3138
ChangeLog

File diff suppressed because it is too large Load Diff

121
MIGRATION.md Normal file
View File

@@ -0,0 +1,121 @@
Date: 2015-june
# Goal:
=======
- support safe concurrency with EWF
- provide a concurrent standalone connector
# Status:
=========
- The version v0 of EWF has mainly 3 connectors: CGI, libFCGI, and nino.
- CGI and libFCGI connectors does not need any concurrency support.
- But the nino connector had a pseudo concurrency support with Thread, however one could do write code that result in hasardeous concurrency execution.
So, it was decided to provide an improved Eiffel web nino connector, and update EWF design to make it concurrency compliant.
# Decisions:
============
- instead of updating current nino library, we now have a new "standalone" connector which is inspired by nino, but have support for the 3 concurrency modes: none, thread and SCOOP.
# Overview
==========
Adding support for SCOOP concurrency mode add constraints to the design, but also helps ensuring the concurrency design of EWF is correct.
As a consequence, we had to introduce a new interface WSF_EXECUTION which is instantiated for each incoming request. See its simplified interface :
<code lang="eiffel">
deferred class WSF_EXECUTION
feature -- Initialization
make (req: WGI_REQUEST; res: WGI_RESPONSE)
do
...
īnitialize
end
initialize
-- Initialize Current object.
--| To be redefined if needed.
do
end
feature -- Access
request: WSF_REQUEST
-- Access to request data.
-- Header, Query, Post, Input data..
response: WSF_RESPONSE
-- Access to output stream, back to the client.
feature -- Execution
execute
-- Execute Current `request',
-- getting data from `request'
-- and response to client via `response'.
deferred
ensure
is_valid_end_of_execution: is_valid_end_of_execution
end
end
</code>
And the related request execution routines are extracted from WSF_SERVICE which becomes almost useless. The "service" part is not mostly responsible of launching the expected connector and set optional options, and declare the type of "execution" interface.
As a result, the well known WSF_DEFAULT_SERVICE has now a formal generic that should conform to WSF_EXECUTION with a `make' creation procedure. See update code:
<code lang="eiffel">
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
end
</code>
Where APPLICATION_EXECUTION is an implementation of the WSF_EXECUTION interface (with the `make' creation procedure).
In addition to add better and safer concurrency support, there are other advantages:
- we now have a clear separation between the service launcher, and the request execution itself.
- the WSF_EXECUTION is created per request, with two main attributes <code>request: WSF_REQUEST</code> and <code>response: WSF_RESPONSE</code>.
# How to migrate to new design
- you can check the various example from the EWF repository, there should all be migrated to new design and comparing previous and new code, this will show you how the migration was done.
- a frequent process:
- identify the root class of your service, (the class implementing the WSF_SERVICE), let us name it APPLICATION_SERVICE
- copy the APPLICATION_SERVICE file to APPLICATION_EXECUTION file.
- change the class name to be APPLICATION_EXECUTION, and replace _SERVICE occurences by _EXECUTION (note the new WSF_ROUTED_EXECUTION and so on, which are mainly migration from previous WSF_ROUTED_SERVICE .., and also WSF_FILTERED_ROUTED_EXECUTION which is new.
- replace "make_and_launch" by "make", remove the initialize redefinition if any.
- in the APPLICATION_SERVICE class, remove most of the ROUTED, FILTERED ... inheritance, and keep WSF_DEFAULT_SERVICE, with a new formal generic i.e WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION].
- in the eventual redefined initialize, remove code related to routers, filters, ...
- remove all the execution related code.
- And you should be done.
- To be short, this is mostly creating a new _EXECUTION class, and move the execution related code into this class from the _SERVICE class.
- Then, you can replace the usage of nino connector by using the new "Standalone" connector, and switch to SCOOP concurrency mode, to ensure you are not messing up with concurrency. Your own code/libraris may not be SCOOP compliant, we recommend to migrate to SCOOP, but as an intermediate solutioņ, you can use the other concurrency mode (none or thread).
Note: the new design impacts the _SERVICE classes, connectors, but WSF_REQUEST, WSF_RESPONSE , WSF_ROUTER are compatible, so the migration is really easy.
We may take the opportunity to update the design deeper according to user feedback, and eventually "wsf" library will be renamed "wsf2".
This is work in progress, all comments , feedback, suggestions, bug report are welcome.
Hopefully before the final version of the new design is out.

View File

@@ -0,0 +1,14 @@
package nino
project
nino = "nino-safe.ecf"
nino = "nino.ecf"
note
title: Eiffel Nino Web Server
description: Simple HTTPd server written in Eiffel
tags: web, httpd, server
license: Eiffel Forum v2
copyright: Javier Velilla, Jocelyn Fiat.
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,211 @@
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/workbook/handling_request/form.md)
## EWF basic service
##### Table of Contents
- [Basic Structure](#structure)
- [Service to Generate Plain Text](#text)
- [Source code](#source_1)
- [Service to Generate HTML](#html)
- [Source code](#source_2)
<a name="structure"/>
## EWF service structure
The following code describes the basic structure of an EWF basic service that handles HTTP requests.
```eiffel
class
SERVICE_TEMPLATE
inherit
WSF_DEFAULT_SERVICE -- Todo explain this, and the concept of launchers and connectors ()
create
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).
```eiffel
class
SERVICE_TEMPLATE
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
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.
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.
![Service Template Hierarchy](/workbook/SERVICE_TEMPLATE.png "Service Template")
**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.
![Launcher Hierarchy](/app/doc/WSF_SERVICE_LAUNCHER.png "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 name="text"/>
## A simple Service to Generate Plain Text.
Before to continue, it is recommended to review the getting started guided.
```eiffel
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
do
-- To send a response we need to setup, the status code and
-- the response headers.
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>)
res.put_string ("Hello World")
end
end
```
<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```
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:
```estudio -config simple.ecf -target simple_nino```
<a name="html"></a>
## A Service to Generate HTML.
To generate HTML, it's needed
1. Change the Content-Type : "text/html"
2. Build an HTML page
```eiffel
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
do
-- To send a response we need to setup, the status code and
-- the response headers.
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
res.put_string (web_page)
end
web_page: STRING = "[
<!DOCTYPE html>
<html>
<head>
<title>Resume</title>
</head>
<body>
Hello World
</body>
</html>
]"
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```
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:
```estudio -config simple_html.ecf -target simple_html_nino```
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/workbook/handling_request/form.md)

View File

@@ -0,0 +1,37 @@
note
description : "Basic Service that Generates Plain Text"
date : "$Date$"
revision : "$Revision$"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
do
-- To send a response we need to setup, the status code and
-- the response headers.
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>)
res.put_string ("Hello World")
end
end

View File

@@ -0,0 +1,42 @@
<?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="simple" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="simple">
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="simple_nino" 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_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="simple" location=".\" recursive="true"/>
</target>
<target name="simple_cgi" 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_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="simple" location=".\" recursive="true"/>
</target>
<target name="simple_libfcgi" 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_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="simple" location=".\" recursive="true"/>
</target>
<target name="simple" extends="simple_nino">
</target>
</system>

View File

@@ -0,0 +1,52 @@
##Run simple_html example on Apache with FCGI on Windows.
####Prerequisites
* This tutorial was written for people working under Windows environment, and using Apache Server with FCGI connector
* Compile the ewf application from command line.
* Assuming you have installed Apache Server under C:/home/server/Apache24.
* Assuming you have placed your current project under C:/home/server/Apache24/fcgi-bin.
* Assuming you have setted the Listen to 8888, the defautl value is 80 .
####FCGI module
If you don't have the FCGI module installed, you can get it from https://www.apachelounge.com/download/, download the module based on your platform [modules-2.4-win64-VC11.zip](https://www.apachelounge.com/download/VC11/modules/modules-2.4-win64-VC11.zip) or [modules-2.4-win32-VC11.zip](https://www.apachelounge.com/download/VC11/modules/modules-2.4-win32-VC11.zip), uncompress it
and copy the _mod_fcgid.so_ to C:/home/server/Apache24/modules
####Compile the project simple_html using the fcgi connector.
ec -config simple_html.ecf -target simple_html_fcgi -finalize -c_compile -project_path .
Copy the genereted exe to C:/home/server/Apache24/fcgi-bin folder.
Check if you have _libfcgi.dll_ in your PATH.
####Apache configuration
Add to httpd.conf the content, you can get the configuration file [here](config.conf)
```
LoadModule fcgid_module modules/mod_fcgid.so
<IfModule mod_fcgid.c>
<Directory "C:/home/server/Apache24/fcgi-bin">
SetHandler fcgid-script
Options +ExecCGI +Includes +FollowSymLinks -Indexes
AllowOverride All
Require all granted
</Directory>
ScriptAlias /simple "C:/home/server/Apache24/fcgi-bin/simple_html.exe"
</IfModule>
```
Test if your httpd.conf is ok
>httpd -t
Luanch the server
>httpd
Check the application
>http://localhost:8888/simple

View File

@@ -0,0 +1,12 @@
LoadModule fcgid_module modules/mod_fcgid.so
<IfModule mod_fcgid.c>
<Directory "C:/home/server/Apache24/fcgi-bin">
SetHandler fcgid-script
Options +ExecCGI +Includes +FollowSymLinks -Indexes
AllowOverride All
Require all granted
</Directory>
ScriptAlias /simple "C:/home/server/Apache24/fcgi-bin/simple_html.exe"
</IfModule>

View File

@@ -0,0 +1,77 @@
note
description : "Basic Service that Generate HTML"
date : "$Date$"
revision : "$Revision$"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
do
-- To send a response we need to setup, the status code and
-- the response headers.
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
res.put_string (web_page)
end
web_page: STRING = "[
<!DOCTYPE html>
<html>
<head>
<title>Resume</title>
</head>
<body>
<div id="header">
<p id="name">Your Name Here</p>
<a href="mailto:you@yourdomain.com"><p id="email">you@yourdomain.com</p></a>
</div>
<div class="left"></div>
<div class="right">
<h4>Objective</h4>
<p>To take a position as a software engineer.</p>
<h4>Experience</h4>
<p>Junior Developer, Software Company (2010 - Present)</p>
<ul>
<li>Designed and implemented end-user features for Flagship Product</li>
<li>Wrote third-party JavaScript and Eiffel libraries</li>
</ul>
<h4>Skills</h4>
<p>Languages: C#, JavaScript, Python, Ruby, Eiffel</p>
<p>Frameworks: .NET, Node.js, Django, Ruby on Rails, EWF</p>
<h4>Education</h4>
<p>BS, Economics, My University</p>
<ul>
<li>Award for best senior thesis</li>
<li>GPA: 3.8</li>
</ul>
</div>
<div id="footer">
<p>123 Your Street, Anytown, State 12345-6789 | Tel: (555) 555-5555</p>
</div>
</body>
</html>
]"
end

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="simple_html" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="simple_html">
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="simple_html_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="simple_html" location=".\" recursive="true"/>
</target>
<target name="simple_html_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="simple_html" location=".\" recursive="true"/>
</target>
<target name="simple_html_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="simple_html" location=".\" recursive="true"/>
</target>
<target name="simple_html" extends="simple_html_nino">
</target>
</system>

View File

@@ -0,0 +1,6 @@
#include <windows.h>
STRINGTABLE
BEGIN
1 "This Program was made using EiffelStudio using Visual Studio C++"
END

View File

@@ -0,0 +1,47 @@
note
description : "Basic Service that show how to use common Status Code"
date : "$Date$"
revision : "$Revision$"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
do
-- To send a response we need to setup, the status code and
-- the response headers.
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/csv"],["Content-Disposition","attachment;filename=Report.xls"],["Content-Length", sheet.count.out]>>)
res.put_string (sheet)
end
-- ,["Content-Disposition","attachment;filename=Report.xls"]
sheet: STRING ="[
Q1 Q2 Q3 Q4 Total
Cherries 78 87 92 29 =SUM(B2:E2)
Grapes 77 86 93 30 =SUM(B3:E3)
]"
end

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="exel" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="exel">l
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="exel_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="exel" location=".\" recursive="true"/>
</target>
<target name="exel_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="exel" location=".\" recursive="true"/>
</target>
<target name="exel_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="exel" location=".\" recursive="true"/>
</target>
<target name="exel" extends="exel_nino">
</target>
</system>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
note
description : "Basic Service that build a generic front end for the most used search engines."
date : "$Date$"
revision : "$Revision$"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
l_message: STRING
do
-- (1) To send a response we need to setup, the status code and the response headers.
-- res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
-- res.put_string (web_page)
-- (2) Using put_header_line
-- res.set_status_code ({HTTP_STATUS_CODE}.ok)
-- res.put_header_line ("Content-Type:text/html")
res.put_header_line ("Content-Length:"+ web_page.count.out)
res.put_header_line ("Content-Type:text/plain")
res.put_string (web_page)
end
feature -- Home Page
web_page: STRING = "[
<!DOCTYPE html>
<html>
<head>
<title>EWF Headers Responses</title>
</head>
<body>
<div class="right">
<h2>Example Header Response</h2>
<p>Response headers</p>
</div>
<div id="footer">
<p>EWF Response Header</p>
</div>
</body>
</html>
]"
end

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="headers" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="headers">
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="headers_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="headers" location=".\" recursive="true"/>
</target>
<target name="headers_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="headers" location=".\" recursive="true"/>
</target>
<target name="headers_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="headers" location=".\" recursive="true"/>
</target>
<target name="headers" extends="headers_nino">
</target>
</system>

View File

@@ -0,0 +1,183 @@
note
description : "Basic Service that build a generic front end for the most used search engines."
date : "$Date$"
revision : "$Revision$"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
l_message: STRING
do
-- To send a response we need to setup, the status code and
-- the response headers.
if req.is_get_request_method then
if req.path_info.same_string ("/") then
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
res.put_string (web_page)
else
send_resouce_not_found (req, res)
end
elseif req.is_post_request_method then
if req.path_info.same_string ("/search") then
if attached {WSF_STRING} req.form_parameter ("query") as l_query then
if attached {WSF_STRING} req.form_parameter ("engine") as l_engine then
if attached {STRING} map.at (l_engine.value) as l_engine_url then
l_engine_url.append (l_query.value)
send_redirect (req, res, l_engine_url)
-- res.redirect_now (l_engine_url)
else
send_bad_request (req, res, " <strong>search engine: " + l_engine.value + "</strong> not supported,<br> try with Google or Bing")
end
else
send_bad_request (req, res, " <strong>search engine</strong> not selected")
end
else
send_bad_request (req, res, " form_parameter <strong>query</strong> is not present")
end
else
send_resouce_not_found (req, res)
end
else
create l_message.make_from_string (message_template)
l_message.replace_substring_all ("$title", "Method Not Allowed")
l_message.replace_substring_all ("$status", "Method Not Allowed 405")
-- Method not allowed
res.put_header ({HTTP_STATUS_CODE}.method_not_allowed, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
res.put_string (l_message)
end
end
feature -- Engine Map
map : STRING_TABLE[STRING]
do
create Result.make (2)
Result.put ("http://www.google.com/search?q=", "Google")
Result.put ("http://www.bing.com/search?q=", "Bing")
end
feature -- Redirect
send_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_location: READABLE_STRING_32)
-- Redirect to `a_location'
local
h: HTTP_HEADER
do
create h.make
h.put_content_type_text_html
h.put_current_date
h.put_location (a_location)
res.set_status_code ({HTTP_STATUS_CODE}.see_other)
res.put_header_text (h.string)
end
feature -- Bad Request
send_bad_request (req: WSF_REQUEST; res: WSF_RESPONSE; description: STRING)
local
l_message: STRING
do
create l_message.make_from_string (message_template)
l_message.replace_substring_all ("$title", "Bad Request")
l_message.replace_substring_all ("$status", "Bad Request" + description)
res.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
res.put_string (l_message)
end
feature -- Resource not found
send_resouce_not_found (req: WSF_REQUEST; res: WSF_RESPONSE)
local
l_message: STRING
do
create l_message.make_from_string (message_template)
l_message.replace_substring_all ("$title", "Resource not found")
l_message.replace_substring_all ("$status", "Resource " + req.request_uri + " not found 404")
res.put_header ({HTTP_STATUS_CODE}.not_found, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
res.put_string (l_message)
end
feature -- Home Page
web_page: STRING = "[
<!DOCTYPE html>
<html>
<head>
<title>Generic Search Engine</title>
</head>
<body>
<div class="right">
<h2>Generic Search Engine</h2>
<form method="POST" action="/search" target="_blank">
<fieldset>
Search: <input type="search" name="query" placeholder="EWF framework"><br>
<div>
<input type="radio" name="engine" value="Google" checked><img src="http://ebizmba.ebizmbainc.netdna-cdn.com/images/logos/google.gif" height="24" width="42">
</div>
<div>
<input type="radio" name="engine" value="Bing"><img src="http://ebizmba.ebizmbainc.netdna-cdn.com/images/logos/bing.gif" height="24" width="42">
</div><br>
</fieldset>
<input type="submit">
</form>
</div>
<div id="footer">
<p><a href="http://www.ebizmba.com/articles/search-engines">Top 15 Most Popular Search Engines | March 2015</a></p>
</div>
</body>
</html>
]"
feature -- Generic Message
message_template: STRING="[
<!DOCTYPE html>
<html>
<head>
<title>$title</title>
</head>
<body>
<div id="header">
<p id="name">Use a tool to see the request and header details, for example (Developers tools in Chrome or Firebugs in Firefox)</p>
</div>
<div class="left"></div>
<div class="right">
<h4>This page is an example of $status</h4>
<div id="footer">
<p><a href="/">Back Home</a></p>
</div>
</body>
</html>
]"
end

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="search" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="search">
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="search_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="search" location=".\" recursive="true"/>
</target>
<target name="search_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="search" location=".\" recursive="true"/>
</target>
<target name="search_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="search" location=".\" recursive="true"/>
</target>
<target name="search" extends="search_nino">
</target>
</system>

View File

@@ -0,0 +1,149 @@
note
description : "Basic Service that a simple web page to show the most common status codes"
date : "$Date$"
revision : "$Revision$"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
l_message: STRING
do
-- To send a response we need to setup, the status code and
-- the response headers.
if req.is_get_request_method then
if req.path_info.same_string ("/") then
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", web_page.count.out]>>)
res.put_string (web_page)
elseif req.path_info.same_string ("/redirect") then
send_redirect (req, res, "https://httpwg.github.io/")
elseif req.path_info.same_string ("/bad_request") then
-- Here you can do some logic for example log, send emails to register the error, before to send the response.
create l_message.make_from_string (message_template)
l_message.replace_substring_all ("$title", "Bad Request")
l_message.replace_substring_all ("$status", "Bad Request 400")
res.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
res.put_string (l_message)
elseif req.path_info.same_string ("/internal_error") then
-- Here you can do some logic for example log, send emails to register the error, before to send the response.
create l_message.make_from_string (message_template)
l_message.replace_substring_all ("$title", "Internal Server Error")
l_message.replace_substring_all ("$status", "Internal Server Error 500")
res.put_header ({HTTP_STATUS_CODE}.internal_server_error, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
res.put_string (l_message)
else
create l_message.make_from_string (message_template)
l_message.replace_substring_all ("$title", "Resource not found")
l_message.replace_substring_all ("$status", "Resource not found 400")
res.put_header ({HTTP_STATUS_CODE}.not_found, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
res.put_string (l_message)
end
else
create l_message.make_from_string (message_template)
l_message.replace_substring_all ("$title", "Method Not Allowed")
l_message.replace_substring_all ("$status", "Method Not Allowed 405")
-- Method not allowed
res.put_header ({HTTP_STATUS_CODE}.method_not_allowed, <<["Content-Type", "text/html"], ["Content-Length", l_message.count.out]>>)
res.put_string (l_message)
end
end
feature -- Home Page
send_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_location: READABLE_STRING_32)
-- Redirect to `a_location'
local
h: HTTP_HEADER
do
create h.make
h.put_content_type_text_html
h.put_current_date
h.put_location (a_location)
res.set_status_code ({HTTP_STATUS_CODE}.see_other)
res.put_header_text (h.string)
end
web_page: STRING = "[
<!DOCTYPE html>
<html>
<head>
<title>Example showing common status codes</title>
</head>
<body>
<div id="header">
<p id="name">Use a tool to see the request and header details, for example (Developers tools in Chrome or Firebugs in Firefox)</p>
</div>
<div class="left"></div>
<div class="right">
<h4>This page is an example of Status Code 200</h4>
<h4> Redirect Example </h4>
<p> Click on the following link will redirect you to the HTTP Specifcation, we can do the redirect from the HTML directly but
here we want to show you an exmaple, where you can do something before to send a redirect <a href="/redirect">Redirect</a></p>
<h4> Bad Request </h4>
<p> Click on the following link, the server will answer with a 400 error, check the status code <a href="/bad_request">Bad Request</a></p>
<h4> Internal Server Error </h4>
<p> Click on the following link, the server will answer with a 500 error, check the status code <a href="/internal_error">Internal Error</a></p>
<h4> Resource not found </h4>
<p> Click on the following link or add to the end of the url something like /1030303 the server will answer with a 404 error, check the status code <a href="/not_foundd">Not found</a></p>
</div>
<div id="footer">
<p>Useful links for status codes <a href="httpstat.us">httpstat.us</a> and <a href="httpbing.org">httpbin.org</a></p>
</div>
</body>
</html>
]"
feature -- Generic Message
message_template: STRING="[
<!DOCTYPE html>
<html>
<head>
<title>$title</title>
</head>
<body>
<div id="header">
<p id="name">Use a tool to see the request and header details, for example (Developers tools in Chrome or Firebugs in Firefox)</p>
</div>
<div class="left"></div>
<div class="right">
<h4>This page is an example of $status</h4>
<div id="footer">
<p><a href="/">Back Home</a></p>
</div>
</body>
</html>
]"
end

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="status" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="status">l
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="status_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="status" location=".\" recursive="true"/>
</target>
<target name="status_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="status" location=".\" recursive="true"/>
</target>
<target name="status_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="status" location=".\" recursive="true"/>
</target>
<target name="status" extends="status_nino">
</target>
</system>

View File

@@ -0,0 +1,153 @@
note
description : "Basic Service that build a generic front to demonstrate the use of Cookies"
date : "$Date$"
revision : "$Revision$"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
set_service_option ("verbose",True)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
l_message: STRING
l_header: HTTP_HEADER
l_time: HTTP_DATE
l_cookies: STRING
l_answer: STRING
do
-- all the cookies
create l_cookies.make_empty
across req.cookies as ic loop
l_cookies.append (ic.item.name)
l_cookies.append("<br>")
end
if req.path_info.same_string ("/") then
create l_header.make
create l_answer.make_from_string (web_page)
if req.cookie ("_EWF_Cookie") = Void then
-- First access the the home page, find a cookie with specific name `_EWF_Cookie'
l_answer.replace_substring_all ("$header_title", "Hey, thanks for access our cool site, this is your first acess")
l_answer.replace_substring_all ("$cookies", l_cookies)
create l_time.make_now_utc
l_time.date_time.day_add (40)
l_header.put_cookie_with_expiration_date ("_EWF_Cookie", "EXAMPLE",l_time.date_time, "", Void, False, True)
else
-- No a new access
l_answer.replace_substring_all ("$header_title", "Welcome back, please check all the new things we have!!!")
l_answer.replace_substring_all ("$cookies", l_cookies)
end
l_header.put_content_type_text_html
l_header.put_content_length (l_answer.count)
res.put_header_text (l_header.string)
res.put_string (l_answer)
elseif req.path_info.same_string ("/visitors") then
create l_header.make
create l_answer.make_from_string (visit_page)
if req.cookie ("_visits") = Void then
-- First access the the visit page, find a cookie with specific name `_visits'
l_answer.replace_substring_all ("$visit", "1")
l_answer.replace_substring_all ("$cookies", l_cookies)
create l_time.make_now_utc
l_time.date_time.day_add (40)
l_header.put_cookie_with_expiration_date ("_visits", "1",l_time.date_time, "/visitors", Void, False, True)
else
if attached {WSF_STRING} req.cookie ("_visits") as l_visit then
create l_time.make_now_utc
l_time.date_time.day_add (40)
l_answer.replace_substring_all ("$visit", (l_visit.value.to_integer + 1).out )
l_answer.replace_substring_all ("$cookies", l_cookies)
l_header.put_cookie_with_expiration_date ("_visits", (l_visit.value.to_integer + 1).out,l_time.date_time, "/visitors", Void, False, True)
end
end
create l_time.make_now_utc
l_time.date_time.second_add (120)
l_header.put_content_type_text_html
-- This cookie expires in 120 seconds, its valid for 120 seconds
l_header.put_cookie_with_expiration_date ("_Framework", "EWF",l_time.date_time, "/", Void, False, True)
-- This is a session cookie, valid only to the current browsing session.
l_header.put_cookie ("Session", "Cookie",Void, "/", Void, False, True)
l_header.put_content_length (l_answer.count)
res.add_header_text (l_header.string)
res.put_string (l_answer)
end
end
feature -- Home Page
web_page: STRING = "[
<!DOCTYPE html>
<html>
<head>
<title>EWF Handling Cookies</title>
</head>
<body>
<div class="right">
<h2>$header_title</h2>
</div>
<div class="right">
<a href="/visitors">Visitors</a>
</div>
<div>
<h3>Cookies for the home page</h3>
$cookies
</div>
</body>
</html>
]"
visit_page: STRING = "[
<!DOCTYPE html>
<html>
<head>
<title>EWF Handling Visit Page</title>
</head>
<body>
<div class="right">
<h2>The number of visits is $visit</h2>
</div>
<div>
<h3>Cookies for the Visit page</h3>
$cookies
</div>
</br>
<div>
Back to <a href="/"> Home </a>
</div>
<div id="footer">
<p>EWF Example Cookies</p>
</div>
</body>
</html>
]"
end

View File

@@ -0,0 +1,42 @@
<?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="example" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="example">
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="example_nino" 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_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="example" location=".\" recursive="true"/>
</target>
<target name="example_cgi" 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_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="example" location=".\" recursive="true"/>
</target>
<target name="example_libfcgi" 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_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="example" location=".\" recursive="true"/>
</target>
<target name="example" extends="example_nino">
</target>
</system>

View File

@@ -0,0 +1,300 @@
Nav: [Workbook](../workbook.md) | [Generating Responses](/workbook/generating_response/generating_response.md)
# Handling Cookies
- [Cookie](#cookie)
- [Cookie Porperties](#properties)
- [Write and Read Cookies](#set_get)
- [How to set a cookie](#set_cookie)
- [How to read a cookie](#read_cookie)
- [Examples](#examples)
<a name="cookie"/>
## [Cookie](http://httpwg.github.io/specs/rfc6265.html)
A cookie is a piece of data that can be stored in a browser's cache. If you visit a web site and then revisit it, the cookie data can be used to identify you as a return visitor. Cookies enable state information, such as an online shopping cart, to be remembered. A cookie can be short term, holding data for a single web session, that is, until you close the browser, or a cookie can be longer term, holding data for a week or a year.
Cookies are used a lot in web client-server communication.
- HTTP State Management With Cookies
- Personalized response to the client based on their preference, for example we can set background color as cookie in client browser and then use it to customize response background color, image etc.
Server send cookies to the client
>Set-Cookie: _Framework=EWF; Path=/; Expires=Tue, 10 Mar 2015 13:28:10 GMT; HttpOnly%R
Client send cookies to server
>Cookie: _Framework=EWF
<a name="properties"/>
### Cookie properties
- Comment: describe the purpose of the cookie. Note that server doesnt receive this information when client sends cookie in request header.
- Domain: domain name for the cookie.
- Expiration/MaxAge: Expiration time of the cookie, we could also set it in seconds. (At the moment Max-Age attribute is not supported)
- Name: name of the cookie.
- Path: path on the server to which the browser returns this cookie. Path instruct the browser to send cookie to a particular resource.
- Secure: True, if the browser is sending cookies only over a secure protocol, False in other case.
- Value: Value of th cookie as string.
- HttpOnly: Checks whether this Cookie has been marked as HttpOnly.
- Version:
<a name="set_get"/>
## Write and Read Cookies.
To send a cookie to the client we should use the [HTTP_HEADER] class, and call ```h.put_cookie``` feature or
```h.put_cookie_with_expiration_date``` feature, see [How to set Cookies]() to learn the details, and the set it to response object [WSF_RESPONSE] as we saw previously.
We will show an example.
To Read incomming cookies we can read all the cookies with
```
cookies: ITERABLE [WSF_VALUE]
-- All cookies.
```
which return an interable of WSF_VALUE objects corresponding to the cookies the browser has associated with the web site.
We can also check if a particular cookie by name using
```
WSF_REQUEST.cookie (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
-- Field for name `a_name'.
```
feature.
<a name="set_cookie"/>
### How to set Cookies
Here we have the feature definitions to set cookies
```eiffel
deferred class interface
HTTP_HEADER_MODIFIER
feature -- Cookie
put_cookie (key, value: READABLE_STRING_8; expiration, path, domain: detachable READABLE_STRING_8; secure, http_only: BOOLEAN)
-- Set a cookie on the client's machine
-- with key 'key' and value 'value'.
-- Note: you should avoid using "localhost" as `domain' for local cookies
-- since they are not always handled by browser (for instance Chrome)
require
make_sense: (key /= Void and value /= Void) and then (not key.is_empty and not value.is_empty)
domain_without_port_info: domain /= Void implies domain.index_of (':', 1) = 0
put_cookie_with_expiration_date (key, value: READABLE_STRING_8; expiration: DATE_TIME; path, domain: detachable READABLE_STRING_8; secure, http_only: BOOLEAN)
-- Set a cookie on the client's machine
-- with key 'key' and value 'value'.
require
make_sense: (key /= Void and value /= Void) and then (not key.is_empty and not value.is_empty)
```
Example of use:
```eiffel
response_with_cookies (res: WSF_RESPONSE)
local
l_message: STRING
l_header: HTTP_HEADER
l_time: HTTP_DATE
do
create l_header.make
create l_time.make_now_utc
l_time.date_time.day_add (40)
l_header.put_content_type_text_html
l_header.put_cookie_with_expiration_date ("EWFCookie", "EXAMPLE",l_time.date_time, "/", Void, False, True)
res.put_header_text (l_header.string)
res.put_string (web_page)
end
```
<a name="read_cookie"/>
### How to read Cookies
Reading a particular cookie
```eiffel
if req.cookie ("EWFCookie") = Void then
do_something
end
````
Reading all the cookies
```Eiffel
across req.cookies as ic loop
print (ic.item.name)
end
```
<a name="examples"/>
### Example
The following EWF service shows a basic use of cookies.
1. It display a message to first-time visitors.
2. Display a welcome back message if a visitor return.
3. A visitor page, counting the number of visits to the page (track user access counts).
4. A cookie with an expiration of 120 seconds.
5. A cookie with an session level, valid in browser session.
```eiffel
note
description : "Basic Service that build a generic front to demonstrate the use of Cookies"
date : "$Date$"
revision : "$Revision$"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
set_service_option ("verbose",True)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
l_message: STRING
l_header: HTTP_HEADER
l_time: HTTP_DATE
l_cookies: STRING
l_answer: STRING
do
-- all the cookies
create l_cookies.make_empty
across req.cookies as ic loop
l_cookies.append (ic.item.name)
l_cookies.append("<br>")
end
if req.path_info.same_string ("/") then
create l_header.make
create l_answer.make_from_string (web_page)
if req.cookie ("_EWF_Cookie") = Void then
-- First access the the home page, find a cookie with specific name `_EWF_Cookie'
l_answer.replace_substring_all ("$header_title", "Hey, thanks for access our cool site, this is your first acess")
l_answer.replace_substring_all ("$cookies", l_cookies)
create l_time.make_now_utc
l_time.date_time.day_add (40)
l_header.put_cookie_with_expiration_date ("_EWF_Cookie", "EXAMPLE",l_time.date_time, "", Void, False, True)
else
-- No a new access
l_answer.replace_substring_all ("$header_title", "Welcome back, please check all the new things we have!!!")
l_answer.replace_substring_all ("$cookies", l_cookies)
end
l_header.put_content_type_text_html
l_header.put_content_length (l_answer.count)
res.put_header_text (l_header.string)
res.put_string (l_answer)
elseif req.path_info.same_string ("/visitors") then
create l_header.make
create l_answer.make_from_string (visit_page)
if req.cookie ("_visits") = Void then
-- First access the the visit page, find a cookie with specific name `_visits'
l_answer.replace_substring_all ("$visit", "1")
l_answer.replace_substring_all ("$cookies", l_cookies)
create l_time.make_now_utc
l_time.date_time.day_add (40)
l_header.put_cookie_with_expiration_date ("_visits", "1",l_time.date_time, "/visitors", Void, False, True)
else
if attached {WSF_STRING} req.cookie ("_visits") as l_visit then
create l_time.make_now_utc
l_time.date_time.day_add (40)
l_answer.replace_substring_all ("$visit", (l_visit.value.to_integer + 1).out )
l_answer.replace_substring_all ("$cookies", l_cookies)
l_header.put_cookie_with_expiration_date ("_visits", (l_visit.value.to_integer + 1).out,l_time.date_time, "/visitors", Void, False, True)
end
end
create l_time.make_now_utc
l_time.date_time.second_add (120)
l_header.put_content_type_text_html
-- This cookie expires in 120 seconds, its valid for 120 seconds
l_header.put_cookie_with_expiration_date ("_Framework", "EWF",l_time.date_time, "/", Void, False, True)
-- This is a session cookie, valid only to the current browsing session.
l_header.put_cookie ("Session", "Cookie",Void, "/", Void, False, True)
l_header.put_content_length (l_answer.count)
res.add_header_text (l_header.string)
res.put_string (l_answer)
end
end
feature -- Home Page
web_page: STRING = "[
<!DOCTYPE html>
<html>
<head>
<title>EWF Handling Cookies</title>
</head>
<body>
<div class="right">
<h2>$header_title</h2>
</div>
<div class="right">
<a href="/visitors">Visitors</a>
</div>
<div>
<h3>Cookies for the home page</h3>
$cookies
</div>
</body>
</html>
]"
visit_page: STRING = "[
<!DOCTYPE html>
<html>
<head>
<title>EWF Handling Visit Page</title>
</head>
<body>
<div class="right">
<h2>The number of visits is $visit</h2>
</div>
<div>
<h3>Cookies for the Visit page</h3>
$cookies
</div>
</br>
<div>
Back to <a href="/"> Home </a>
</div>
<div id="footer">
<p>EWF Example Cookies</p>
</div>
</body>
</html>
]"
end
```
Nav: [Workbook](../workbook.md) | [Generating Responses](/workbook/generating_response/generating_response.md)

View File

@@ -0,0 +1,309 @@
Nav: [Workbook](../workbook.md) | [Basic Concepts] (/workbook/basics/basics.md) | [Handling Requests: Header Fields](/workbook/handling_request/headers.md)
#Handling Requests: Form/Query Data
##### Table of Contents
- [Reading Form Data](#read)
- [Query Parameters](#query)
- [Form Parameters](#form)
- [Uniform Read](#uniform)
- [Reading Parameters and Values](#reading_pv)
- [How to read all parameters names](#all_names)
- [How to read single values](#single_values)
- [How to read multiple values](#multiple_values)
- [How to read table values](#table_values)
- [Reading raw data](#raw_data)
- [Upload Files](#upload)
- [Examples](#examples)
An HTML Form can handle GET and POST requests.
When we use a form with method GET, the data is attached at the end of the url for example:
>http://wwww.example.com?key1=value1&...keyn=valuen
If we use the method POST, the data is sent to the server in a different line.
Extracting form data from the server side is one of the most tedious parts. If you do it by hand, you will need
to parse the input, you'll have to URL-decode the value.
Here we will show you how to read input submitted by a user using a Form (GET and POST).
* How to handle missing values:
* client side validattion, server side validations, set default if it's a valid option.
* How to populate Eiffel objects from the request data.
<a name="read"/>
## Reading Form Data
EWF [WSF_REQUEST]() class, provides features to handling this form parsing automatically.
<a name="query"/>
### Query Parameters
WSF_REQUEST.query_parameters: ITERABLE [WSF_VALUE]
-- All query parameters
WSF_REQUEST.query_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
-- Query parameter for name `a_name'.
<a name="form"/>
### Form Parameters
WSF_REQUEST.form_parameters: ITERABLE [WSF_VALUE]
-- All form parameters sent by a POST
WSF_REQUEST.form_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
-- Field for name `a_name'.
The values supplied to form_parameter and query_parameter are case sensitive.
<a name="uniform"/>
### Read Data
The previous features, let you read the data one way for GET request and a different way for POST request. WSF_REQUEST provide a feature to read all the data in a uniform way.
WSF_REQUEST.item (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
-- Variable named `a_name' from any of the variables container
-- and following a specific order: form_, query_ and path_ parameters
So, you use **WSF_REQUEST.item** feature exactly the same way for GET and POST request.
>Note: if a query parameter has the same name as a form paramenter req.item will retrieve the form paramenter. Remember the precedence: form > query > path
<a name="reading_pv">
## Reading Parameters and Values
Suppose we have the following HTML5 form using Method POST. This HTML5 form has client side form validation using the new HTML5 attribute, you can do the same using Javascript. So in this case if the user does not fill the fields as expected the form will not be submitted to the server.
>Note: You want to validate on the server side because you can protect against the malicious user, who can easily bypass your JavaScript and submit dangerous input to the server.
```
<h1> EWF Handling Client Request: Form example </h1>
<form action="/" method="POST">
<fieldset>
<legend>Personal details</legend>
<div>
<label>First Name
<input id="given-name" name="given-name" type="text" placeholder="First name only" required autofocus>
</label>
</div>
<div>
<label>Last Name
<input id="family-name" name="family-name" type="text" placeholder="Last name only" required autofocus>
</label>
</div>
<div>
<label>Email
<input id="email" name="email" type="email" placeholder="example@domain.com" required>
</label>
</div>
<div>
<label>Languages
<input type="checkbox" name="languages" value="Spanish"> Spanish
<input type="checkbox" name="languages" value="English"> English
</label>
</div>
</fieldset>
<fieldset>
<div>
<button type=submit>Submit Form</button>
</div>
</fieldset>
</form>
```
<a name="all_names">
### How to read all parameter names
To read all the parameters names we simple call WSF_REQUEST.form_parameters.
```
req: WSF_REQUEST
across req.form_parameters as ic loop show_parameter_name (ic.item.key) end
```
<a name="single_values">
### How to read single values
To read a particular parameter, a single value, for example `given-name', we simple call WSF_REQUEST.form_parameter (a_name) and we check if it's attached to WSF_STRING (represents a String parameter)
```
req: WSF_REQUEST
if attached {WSF_STRING} req.form_paramenter ('given-name') as l_given_name then
-- Work with the given parameter, for example populate an USER object
-- the argument is case sensitive
else
-- Value missing, check the name against the HTML form
end
```
<a name="multiple_values">
### How to read multiple values
To read multiple values, for example in the case of `languages', we simple call WSF_REQUEST.form_parameter (a_name) and we check if it's attached to WSF_MULTIPLE_STRING (represents a String parameter)
```
req: WSF_REQUEST
idioms: LIST[STRING]
-- the argument is case sensitive
if attached {WSF_MULTIPLE_STRING} req.form_paramenter ('languages') as l_languages then
-- Work with the given parameter, for example populate an USER object
-- Get all the associated values
create {ARRAYED_LIST[STRING]} idioms.make (2)
across l_languages as ic loop idioms.force (ic.item.value) end
elseif attached {WSF_STRING} req.form_paramenter ('languages') as l_language then
-- Value missing, check the name against the HTML form
create {ARRAYED_LIST[STRING]} idioms.make (1)
idioms.force (l_language.value)
else
-- Value missing
end
```
In this case we are handling strings values, but in some cases you will need to do a conversion, betweend the strings that came from the request to map them to your domain model.
<a name="table_values">
### How to read table values
This is particularly useful when you have a request with the following format
``` <a href="/link?tab[a]=1&tab[b]=2&tab[c]=foo"> ```
To read table values, for example in the case of `tab', we simple call WSF_REQUEST.form_parameter (a_name) and we check if it's attached to WSF_TABLE.
```
if attached {WSF_TABLE} req.query_parameter ("tab") as l_tab then
l_parameter_names.append ("<br>")
l_parameter_names.append (l_tab.name)
from
l_tab.values.start
until
l_tab.values.after
loop
l_parameter_names.append ("<br>")
l_parameter_names.append (l_tab.values.key_for_iteration)
if attached {WSF_STRING} l_tab.value (l_tab.values.key_for_iteration) as l_value then
l_parameter_names.append ("=")
l_parameter_names.append (l_value.value)
end
l_tab.values.forth
end
end
```
<a name="raw_data">
## Reading Raw Data
You can also access the data in raw format, it means you will need to parse and url-decode it, and also you will not be able to use the previous features, by default, to enable that you need to call `req.set_raw_input_data_recorded (True)'. This feature (reading raw data) is useful if you are reading POST data with JSON or XML formats, but it's not convinient for HTML forms.
To read raw data you need to do this
```
l_raw_data:STRING
req.set_raw_input_data_recorded (True) --
create l_raw_data.make_empty
req.read_input_data_into (l_raw_data)
```
> given-name=testr&family-name=test&dob=1976-08-26&email=test%40gmail.com&url=http%3A%2F%2Fwww.eiffelroom.com&phone=455555555555&languages=Spanish&languages=English
<a name=upload></a>
## Upload Files
How can we read data when the date come from an uploaded file/s?.
HTML supports a form element ```<input type="File" ... > ``` to upload a single file and ```<input type="File" ... multiplr> ``` to upload multiple files.
So supose we have the following form
```
<!DOCTYPE html>
<html>
<head>
<title>EWF Handling Client Request: File Upload Example</title>
</head>
<body>
<h1> EWF Handling Client Request: File Upload Example</h1>
<form action="/upload" enctype="multipart/form-data" method="POST">
<fieldset>
<legend>Upload file/s</legend>
<div>
<label>File
<input name="file-name[]" type="file" multiple>
</label>
<fieldset>
<div>
<button type=submit>Send</button>
</div>
</fieldset>
</form>
</body>
</html>
```
The class WSF_REQUEST has defines mechanism to work with uploaded files. We can call the query
```
WSF_REQUEST.has_uploaded_file: BOOLEAN
-- Has any uploaded file?
```
to check if the request form parameters has any uploaded file, and we can call the feature
```
WSF_REQUEST.uploaded_files: ITERABLE [WSF_UPLOADED_FILE]
-- uploaded files values
--| filename: original path from the user
--| type: content type
--| tmp_name: path to temp file that resides on server
--| tmp_base_name: basename of `tmp_name'
--| error: if /= 0 , there was an error : TODO ...
--| size: size of the file given by the http request
```
to iterate over the uploaded files if any, and the details in the class [WSF_UPLOADED_FILE].
The following snipet code show how to work with Uploaded files using EWF [WSF_REQUEST] class, in the example
we build a simple html answer with basic information, if there is not uploaded files, we send a 400 status code
and a simple message.
```eiffel
if req.path_info.same_string ("/upload") then
-- Check if we have an uploaded file
if req.has_uploaded_file then
-- iterate over all the uploaded files
create l_answer.make_from_string ("<h1>Uploaded File/s</h1><br>")
across req.uploaded_files as ic loop
l_answer.append ("<strong>FileName:</strong>")
l_answer.append (ic.item.filename)
l_answer.append ("<br><strong>Size:</strong>")
l_answer.append (ic.item.size.out)
l_answer.append ("<br>")
end
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-type","text/html"],["Content-lenght", l_answer.count.out]>>)
res.put_string (l_answer)
else
-- Here we should handle unexpected errors.
create l_answer.make_from_string ("<strong>No uploaded files</strong><br>")
create l_answer.append ("Back to <a href='/'>Home</a>")
res.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-type","text/html"],["Content-lenght", l_answer.count.out]>>)
res.put_string (l_answer)
end
else
-- Handle error
end
```
The source code is available on Github. You can get it by running the command:
```git clone https://github.com/EiffelWebFramework/ewf_examples.git```
The example is located in the directory $PATH/ewf_examples/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```
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
```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)

View File

@@ -0,0 +1,112 @@
note
description : "Basic Service that show how to handle a GET request"
date : "$Date$"
revision : "$Revision$"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
file: WSF_FILE_RESPONSE
l_parameter_names: STRING
l_answer: STRING
idioms: LIST[STRING]
l_raw_data: STRING
do
if req.is_get_request_method then
if req.path_info.same_string ("/") then
create file.make_html ("form.html")
res.send (file)
elseif req.path_info.same_string ("/search") then
-- (1) the parameter is case sensitive
if not (attached req.query_parameter ("GIVEN-NAME")) then
-- Wrong `GIVEN-NAME' need to be in lower case.
end
-- (2) Multiple values
if attached {WSF_MULTIPLE_STRING} req.query_parameter ("languages") as l_languages then
-- Get all the associated values
create {ARRAYED_LIST[STRING]} idioms.make (2)
across l_languages as ic loop idioms.force (ic.item.value) end
elseif attached {WSF_STRING} req.query_parameter ("languages") as l_language then
-- Single value
print (l_language.value)
else
-- Value Missing
end
-- Read the all parameters names and his values.
create l_parameter_names.make_from_string ("<h2>Parameters Names</h2>")
l_parameter_names.append ("<br>")
create l_answer.make_from_string ("<h2>Parameter Names and Values</h2>")
l_answer.append ("<br>")
across req.query_parameters as ic loop
l_parameter_names.append (ic.item.key)
l_parameter_names.append ("<br>")
l_answer.append (ic.item.key)
l_answer.append_character ('=')
if attached {WSF_STRING} req.query_parameter (ic.item.key) as l_value then
l_answer.append_string (l_value.value)
end
l_answer.append ("<br>")
end
l_parameter_names.append ("<br>")
l_parameter_names.append_string (l_answer)
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>)
res.put_string (l_parameter_names)
elseif req.path_info.same_string ("/link") then
-- WSF_TABLE example
create l_parameter_names.make_from_string ("<h2>Parameters Name</h2>")
if attached {WSF_TABLE} req.query_parameter ("tab") as l_tab then
l_parameter_names.append ("<br>")
l_parameter_names.append (l_tab.name)
from
l_tab.values.start
until
l_tab.values.after
loop
l_parameter_names.append ("<br>")
l_parameter_names.append (l_tab.values.key_for_iteration)
if attached {WSF_STRING} l_tab.value (l_tab.values.key_for_iteration) as l_value then
l_parameter_names.append ("=")
l_parameter_names.append (l_value.value)
end
l_tab.values.forth
end
l_parameter_names.append ("<br>")
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>)
res.put_string (l_parameter_names)
end
else
-- Here we should handle unexpected errors.
end
end
end
end

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="form" library_target="form">
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="form_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="form" location=".\" recursive="true"/>
</target>
<target name="form_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="form" location=".\" recursive="true"/>
</target>
<target name="form_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="form" location=".\" recursive="true"/>
</target>
<target name="form" extends="form_nino">
</target>
</system>

View File

@@ -0,0 +1,49 @@
<!DOCTYPE html>
<html>
<head>
<title>EWF Handling Client Request: Search Form example </title>
</head>
<body>
<h1> EWF Handling Search Request: Form example </h1>
<form action="/search" method="GET">
<fieldset>
<legend>Search by</legend>
<div>
<label>First Name
<input id="given-name" name="given-name" type="text" placeholder="First name only" autofocus>
</label>
</div>
<div>
<label>Last Name
<input id="family-name" name="family-name" type="text" placeholder="Last name only" autofocus>
</label>
</div>
<div>
<label>Date of Birth
<input id="dob" name="dob" type="date">
</label>
</div>
<div>
<label>Email
<input id="email" name="email" type="email" placeholder="example@domain.com">
</label>
</div>
<div>
<label>Languages
<input type="checkbox" name="languages" value="Spanish"> Spanish
<input type="checkbox" name="languages" value="English"> English
</label>
</div>
</fieldset>
<fieldset>
<div>
<button type=submit>Submit Form</button>
</div>
</fieldset>
</form>
<h2> Example link </h2>
<div>
<a href="/link?tab[a]=1&tab[b]=2&tab[c]=foo">Link</a>
</div>
</body>
</html>

View File

@@ -0,0 +1,94 @@
note
description : "Reading Parameters from a HTML FORM (method POST) "
date : "$Date$"
revision : "$Revision$"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
file: WSF_FILE_RESPONSE
l_parameter_names: STRING
l_answer: STRING
idioms: LIST[STRING]
l_raw_data: STRING
do
if req.is_get_request_method then
create file.make_html ("form.html")
res.send (file)
elseif req.is_post_request_method then
req.set_raw_input_data_recorded (True)
-- (3) Read Raw Data
create l_raw_data.make_empty
req.read_input_data_into (l_raw_data)
-- (1) the parameter is case sensitive
if not (attached req.form_parameter ("GIVEN-NAME")) then
-- Wrong `GIVEN-NAME' need to be in lower case.
end
-- (2) Multiple values
if attached {WSF_MULTIPLE_STRING} req.form_parameter ("languages") as l_languages then
-- Get all the associated values
create {ARRAYED_LIST[STRING]} idioms.make (2)
across l_languages as ic loop idioms.force (ic.item.value) end
elseif attached {WSF_STRING} req.form_parameter ("langauges") as l_language then
-- Single value
print (l_language.value)
else
-- Value Missing
end
-- Read the all parameters names and his values.
create l_parameter_names.make_from_string ("<h2>Parameters Names</h2>")
l_parameter_names.append ("<br>")
create l_answer.make_from_string ("<h2>Parameter Names and Values</h2>")
l_answer.append ("<br>")
across req.form_parameters as ic loop
l_parameter_names.append (ic.item.key)
l_parameter_names.append ("<br>")
l_answer.append (ic.item.key)
l_answer.append_character ('=')
if attached {WSF_STRING} req.form_parameter (ic.item.key) as l_value then
l_answer.append_string (l_value.value)
end
l_answer.append ("<br>")
end
l_parameter_names.append ("<br>")
l_parameter_names.append_string (l_answer)
l_parameter_names.append ("<br>")
l_parameter_names.append ("<h2>Raw content</h2>")
l_parameter_names.append (l_raw_data)
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_parameter_names.count.out]>>)
res.put_string (l_parameter_names)
else
-- Here we should handle unexpected errors.
end
end
end

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="form" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="form">
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="form_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="form" location=".\" recursive="true"/>
</target>
<target name="form_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="form" location=".\" recursive="true"/>
</target>
<target name="form_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="form" location=".\" recursive="true"/>
</target>
<target name="form" extends="form_nino">
</target>
</system>

View File

@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<title>EWF Handling Client Request: Form example </title>
</head>
<body>
<h1> EWF Handling Client Request: Form example </h1>
<form action="/" method="POST">
<fieldset>
<legend>Personal details</legend>
<div>
<label>First Name
<input id="given-name" name="given-name" type="text" placeholder="First name only" required autofocus>
</label>
</div>
<div>
<label>Last Name
<input id="family-name" name="family-name" type="text" placeholder="Last name only" required autofocus>
</label>
</div>
<div>
<label>Date of Birth
<input id="dob" name="dob" type="date" required>
</label>
</div>
<div>
<label>Email
<input id="email" name="email" type="email" placeholder="example@domain.com" required>
</label>
</div>
<div>
<label>URL
<input id="url" name="url" type="url" placeholder="http://mysite.com">
</label>
</div>
<div>
<label>Telephone
<input id="phone" name="phone" type="tel" placeholder="Eg. +447000 000000" required>
</label>
</div>
<div>
<label>Languages
<input type="checkbox" name="languages" value="Spanish"> Spanish
<input type="checkbox" name="languages" value="English"> English
</label>
</div>
</fieldset>
<fieldset>
<div>
<button type=submit>Submit Form</button>
</div>
</fieldset>
</form>
</body>
</html>

View File

@@ -0,0 +1,457 @@
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/workbook/handling_request/form.md) | [Generating Responses](/workbook/generating_response/generating_response.md)
#Handling Requests: Headers
##### Introduction
- The [HTTP request header fields (also known as "headers")](https://httpwg.github.io/specs/rfc7231.html#request.header.fields) are set by the client (usually web browser) and sent in the header of the http request text (see http protocol), as opposed to form or query parameters [Form Data]().
- Query parameters are encoded in the URL [GET requests](https://httpwg.github.io/specs/rfc7230.html#http.message).
- Form parameters are encoded in the request message for [POST/PUT requests.](https://httpwg.github.io/specs/rfc7230.html#http.message).
A request usually includes the header fields [Accept, Accept-Encoding, Connection, Cookie, Host, Referer, and User-Agent](https://httpwg.github.io/specs/rfc7231.html#request.header), defining important information about how the server should process the request. And then, the server needs to read the request header fields to use those informations.
##### Table of Contents
- [Reading HTTP Header fields](#read_header)
- [Reading HTTP Request line](#read_line)
- [Understanding HTTP header fields](#understand)
- [Accept](#accept)
- [Accept-Charset](#accept_charset)
- [Accept-Encoding](#accept_encoding)
- [Accept-Language](#accept_language)
- [Connection](#connection)
- [Authorization](#authorization)
- [Content-length](#content-length)
- [Cookie](#cookie)
- [Host](#host)
- [If-Modified-Since](#if-modified-since)
- [If-Unmodified-Since](#if-unmodified-since)
- [Referer](#referer)
- [User-Agent](#user-agent)
- [Example: Request Headers](#example)
- [Example: How to compress pages](#compress)
- [Example: Detecting Browser Types](#browser-types)
- [Example: CGI Variables](#cgi-variables)
That section explains how to read HTTP information sent by the browser via the request header fields. Mostly by defining the most important HTTP request header fields, for more information, read [HTTP 1.1 specification](https://httpwg.github.io/specs/).
## Prerequisites
The Eiffel Web Framework is using the traditional Common Gateway Interface (CGI) programming interface to access the header fields, query and form parameters.
Among other, this means the header fields are exposed with associated CGI field names:
- the header field name are uppercased, and any dash "-" replaced by underscore "_".
- and also prefixed by "HTTP_" except for CONTENT_TYPE and CONTENT_LENGTH.
- For instance `X-Server` will be known as `HTTP_X_SERVER`.
<a name="read_header"></a>
## Reading HTTP Header fields
EWF [WSF_REQUEST]() class provides features to access HTTP headers.
Reading most headers is straightforward by calling:
- the corresponding `http_*` functions such as `http_accept` for header "Accept".
- or indirectly using the `meta_string_variable (a_name)` function by passing the associated CGI field name.
In both cases, if the related header field is supplied by the request, the result is a string value, otherwise it is Void.
Note: always check if the result of those functions is non-void before using it.
* Cookies:
- To iterate on all cookies valued, use `cookies: ITERABLE [WSF_VALUE]`
- To retrieve a specific cookie value, use `cookie (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE`
* Authorization
- To read the Authorization header, first check its type with: `auth_type: detachable READABLE_STRING_8`
- And its value via `http_authorization: detachable READABLE_STRING_8 --Contents of the Authorization: header from the current wgi_request, if there is one.`
* Content_length
- If supplied, get the content length as an string value: `content_length: detachable READABLE_STRING_8`
- or directly as a natural value with `content_length_value: NATURAL_64`
* Content_type
- If supplied, get the content type as an string value with `content_type: detachable HTTP_CONTENT_TYPE`
Due to CGI compliance, the original header names are not available, however the function `raw_header_data` may return the http header data as a string value (warning: this may not be available, depending on the underlying connector). Apart from very specific cases (proxy, debugging, ...), it should not be useful.
Note: CGI variables are information about the current request (and also about the server). Some are based on the HTTP request line and headers (e.g., form parameters, query parameters), others are derived from the socket itself (e.g., the name and IP address of the requesting host), and still others are taken from server installation parameters (e.g., the mapping of URLs to actual paths).
<a name="read_line"></a>
####Retrieve information from the Request Line
For convenience, the following sections refer to a request starting with line:
```
GET http://eiffel.org/search?q=EiffelBase HTTP/1.1
```
Overview of the features
* HTTP method
- The function `request_method: READABLE_STRING_8` gives access to the HTTP request method, (usually GET or POST in conventional Web Applications), but with the raise of REST APIs other methods are also frequently used such as HEAD, PUT, DELETE, OPTIONS, or TRACE.
A few functions helps determining quickly the nature of the request method:
- `is_get_request_method: BOOLEAN -- Is Current a GET request method?`
- `is_put_request_method: BOOLEAN -- Is Current a PUT request method?`
- `is_post_request_method: BOOLEAN -- Is Current a POST request method?`
- `is_delete_request_method: BOOLEAN -- Is Current a DELETE request method?`
In our example the request method is `GET`
* Query String
- The query string for the example is `q=EiffelBase`
- `query_string: READABLE_STRING_8`
* Protocol
- The feature return the third part of the request line, which is generally HTTP/1.0 or HTTP/1.1.
- `server_protocol: READABLE_STRING_8`
In the example the request method is `HTTP/1.1`
<a name="understand"></a>
#### Understanding HTTP 1.1 Request Headers
Access to the request headers permits the web server applications or APIs to perform optimizations and provide behavior that would not be possible without them for instance such as adapting the response according to the browser preferences.
This section summarizes the headers most often used; for more information, see the [HTTP 1.1 specification](https://httpwg.github.io/specs/), note that [RFC 2616 is dead](https://www.mnot.net/blog/2014/06/07/rfc2616_is_dead).
<a name="accept"></a>
* [Accept](https://httpwg.github.io/specs/rfc7231.html#header.accept)
- The "Accept" header field can be used by user agents (browser or other clients) to define response media types that are acceptable. Accept header fields can be used to indicate that the request is limited to a small set of desired types, as in the case of a request for an inline image.
For example, assume an APIs Learn4Kids can respond with XML or JSON data (JSON format have some advantages over XML, readability, parsing etc...), a client can define its preference using "Accept: application/json" to request data in JSON format, or "Accept: application/xml" to get XML format. In other case the server sends a not acceptable response. Note that the client can define an ordered list of accepted content types, including "*", the client will get the response and know the content type via the response header field "Content-Type". Related [Content-Negotiation]()
<a name="accept_charset"></a>
* [Accept-Charset](https://httpwg.github.io/specs/rfc7231.html#header.accept-charset)
- The "Accept-Charset" header field can be sent by a user agent (browser or other clients) to indicate which charsets are acceptable in textual response content (e.g., ISO-8859-1).
<a name="accept_encoding"></a>
* [Accept-Encoding](https://httpwg.github.io/specs/rfc7231.html#header.accept-encoding)
- The "Accept-Encoding" header field can be used by user agents (browser or other clients) to indicate which response content-codings (`gzip`, `compress`) are acceptable in the response. An "identity" token is used as a synonym for "no encoding" in order to communicate when no encoding is preferred. If the server receives this header, it is free to encode the page by using one of the content-encodings specified (usually to reduce transmission time), sending the `Content-Encoding` response header to indicate that it has done so.
<a name="accept_language"></a>
* [Accept-Language](https://httpwg.github.io/specs/rfc7231.html#header.accept-language)
- The "Accept-Language" header field can be used by user agents (browser or other client) to indicate the set of natural languages that are preferred in the response in case the server can produce representation in more than one language. The value of the header should be one of the standard language codes such as en, en-us, da, etc. See RFC 1766 for details (start at http://www.rfc-editor.org/ to get a current list of the RFC archive sites).
<a name="connection"></a>
* [Connection](https://httpwg.github.io/specs/rfc7230.html#header.connection)
- The "Connection" header field allows the sender to indicate desired control options for the current connection, for example if it can hanlde persistent HTTP connections.
By default HTTP/1.1 uses "persistent connections", allowing multiple requests and responses to be carried over a single connection. The "close" connection option is used to signal that a connection will not persist after the current request/response.
<a name="authorization"></a>
* [Authorization](https://httpwg.github.io/specs/rfc7235.html#header.authorization)
- The header is used by user agents to authenticate themselves when accessing password protected resources.
<a name="content-length"></a>
* [Content-Length](https://httpwg.github.io/specs/rfc7230.html#header.content-length)
- For messages that includes a payload body, the Content-Length field-value provides the framing information necessary to determine where the body (and message) ends.
<a name="cookie"></a>
* [Cookie](https://httpwg.github.io/specs/rfc6265.html)
- The Cookie header contains cookies received by the user agent in previous Set-Cookie headers. The origin server is free to ignore the Cookie header or use its contents for an application-specific purpose. (Related State Management).
<a name="host"></a>
* [Host](https://httpwg.github.io/specs/rfc7230.html#header.host)
- The "Host" header field provides the host and port information from the target URI, enabling the origin server to distinguish among resources while serving requests for multiple host names on a single IP address. In HTTP 1.1, browsers and other clients are required to specify this header, which indicates the host and port as given in the original URL.
<a name="if-modified-since"></a>
* [If-Modified-Since](https://httpwg.github.io/specs/rfc7232.html#header.if-modified-since)
- The "If-Modified-Since" header field makes a GET or HEAD request method conditional on the selected representation's modification date being more recent than the date provided in the field-value. Transfering of the selected representation's data is avoided if that data has not changed. So, indicates that the user agents wants the page only if it has been changes after the specified date. The server sends a 304 resource not modified if not has a newer result representation available.
<a name="if-unmodified-since"></a>
* [If-Unmodified-Since](https://httpwg.github.io/specs/rfc7232.html#header.if-unmodified-since)
- The "If-Unmodified-Since" header field makes the request method conditional on the selected representation's last modification date being earlier than or equal to the date provided in the field-value. The operation should succeed only if the document is older than the specified date.
Generally, If-Modified-Since is used for GET requests (“give me the document only if it is newer than my cached version”), whereas If-Unmodified-Since is used for PUT requests (“update this document only if nobody else has changed it since I generated it”).
<a name="referer"></a>
* [Referer](https://httpwg.github.io/specs/rfc7231.html#header.referer)
- The "Referer" header field allows the user agent to specify a URI reference for the resource from which the target URI was obtained (i.e., the "referrer", though the field name is misspelled). A user agent MUST NOT include the fragment and userinfo components of the URI reference [RFC3986], if any, when generating the Referer field value. This header indicates the URL of the referring Web page.
For example, if you are at Web page A and click on a link to Web page B, the URL of Web page A is
included in the Referer header when the browser requests Web page B.
<a name="user-agent"></a>
* [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.
<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 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
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
set_service_option ("verbose", true)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
l_raw_data: STRING
l_page_response: STRING
l_rows: STRING
do
create l_page_response.make_from_string (html_template)
if req.path_info.same_string ("/") then
-- HTTP method
l_page_response.replace_substring_all ("$http_method", req.request_method)
-- URI
l_page_response.replace_substring_all ("$uri", req.path_info)
-- Protocol
l_page_response.replace_substring_all ("$protocol", req.server_protocol)
-- Fill the table rows with HTTP Headers
create l_rows.make_empty
across req.meta_variables as ic loop
if ic.item.name.starts_with ("HTTP_") then
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append (ic.item.name)
l_rows.append ("</td>")
l_rows.append ("<td>")
l_rows.append (ic.item.value)
l_rows.append ("</td>")
l_rows.append ("</tr>")
end
end
l_page_response.replace_substring_all ("$rows", l_rows)
-- Reading the raw header
if attached req.raw_header_data as l_raw_header then
l_page_response.replace_substring_all ("$raw_header", l_raw_header)
end
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>)
res.put_string (l_page_response)
end
end
html_template: STRING = "[
<!DOCTYPE html>
<html>
<head>
<style>
thead {color:green;}
tbody {color:blue;}
table, th, td {
border: 1px solid black;
}
</style>
</head>
<body>
<h1>EWF service example: Showing Request Headers</h1>
<strong>HTTP METHOD:</strong>$http_method<br/>
<strong>URI:</strong>$uri<br>
<strong>PROTOCOL:</strong>$protocol<br/>
<strong>REQUEST TIME:</strong>$time<br/>
<br>
<table>
<thead>
<tr>
<th>Header Name</th>
<th>Header Value</th>
</tr>
</thead>
<tbody>
$rows
</tbody>
</table>
<h2>Raw header</h2>
$raw_header
</body>
</html>
]"
end
```
<a name="compress"></a>
#### How to compress pages
To be completed.
<a name="browser-types"></a>
#### 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 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
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
set_service_option ("verbose", true)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
l_raw_data: STRING
l_page_response: STRING
l_rows: STRING
do
create l_page_response.make_from_string (html_template)
if req.path_info.same_string ("/") then
-- retrieve the user-agent
if attached req.http_user_agent as l_user_agent then
l_page_response.replace_substring_all ("$user_agent", l_user_agent)
l_page_response.replace_substring_all ("$browser", browser_name (l_user_agent))
else
l_page_response.replace_substring_all ("$user_agent", "[]")
l_page_response.replace_substring_all ("$browser", "Unknown, the user-agent was not present.")
end
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>)
res.put_string (l_page_response)
end
end
feature -- Browser utility
browser_name (a_user_agent: READABLE_STRING_8): READABLE_STRING_32
-- Browser name.
-- Must contain Must not contain
-- Firefox Firefox/xyz Seamonkey/xyz
-- Seamonkey Seamonkey/xyz
-- Chrome Chrome/xyz Chromium/xyz
-- Chromium Chromium/xyz
-- Safari Safari/xyz Chrome/xyz
-- Chromium/xyz
-- Opera OPR/xyz [1]
-- Opera/xyz [2]
-- Internet Explorer ;MSIE xyz; Internet Explorer doesn't put its name in the BrowserName/VersionNumber format
do
if
a_user_agent.has_substring ("Firefox") and then
not a_user_agent.has_substring ("Seamonkey")
then
Result := "Firefox"
elseif a_user_agent.has_substring ("Seamonkey") then
Result := "Seamonkey"
elseif a_user_agent.has_substring ("Chrome") and then not a_user_agent.has_substring ("Chromium")then
Result := "Chrome"
elseif a_user_agent.has_substring ("Chromium") then
Result := "Chromiun"
elseif a_user_agent.has_substring ("Safari") and then not (a_user_agent.has_substring ("Chrome") or else a_user_agent.has_substring ("Chromium")) then
Result := "Safari"
elseif a_user_agent.has_substring ("OPR") or else a_user_agent.has_substring ("Opera") then
Result := "Opera"
elseif a_user_agent.has_substring ("MSIE") or else a_user_agent.has_substring ("Trident")then
Result := "Internet Explorer"
else
Result := "Unknown"
end
end
html_template: STRING = "[
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>EWF service example: Showing Browser Dectection Using User-Agent</h1> <br>
<strong>User Agent:</strong> $user_agent <br>
<h2>Enjoy using $browser </h2>
</body>
</html>
]"
end
```
Let see some results, we will show the html returned
Internet Explorer
---
```
<h1>EWF service example: Showing Browser Dectection Using User-Agent</h1></br>
<strong>User Agent:</strong> Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; MDDCJS; rv:11.0) like Gecko <br>
<h2> Enjoy using Internet Explorer </h2>
```
Chrome
---
```
<h1>EWF service example: Showing Browser Dectection Using User-Agent</h1></br>
<strong>User Agent:</strong> Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.91 Safari/537.36 <br>
<h2> Enjoy using Chrome </h2>
```
As an exercise, try to write a similar service to retrieve the OS family using the User-Agent information.
<a name="cgi-variables"></a>
[Meta-variables](https://tools.ietf.org/html/rfc3875#section-4.1) contains data about the request, they are identified by case-insensitive names. In this section, the purpose is to show a similar example to HEADERS FIELDS, but in this case building a table showing the standard CGI variables.
* [AUTH_TYPE](https://tools.ietf.org/html/rfc3875#section-4.1.1).
* [CONTENT_LENGTH](https://tools.ietf.org/html/rfc3875#section-4.1.2)
* [CONTENT_TYPE](https://tools.ietf.org/html/rfc3875#section-4.1.3)
* [GATEWAY_INTERFACE](https://tools.ietf.org/html/rfc3875#section-4.1.4)
* [PATH_INFO](https://tools.ietf.org/html/rfc3875#section-4.1.5)
* [PATH_TRANSLATED](https://tools.ietf.org/html/rfc3875#section-4.1.6)
* [QUERY_STRING](https://tools.ietf.org/html/rfc3875#section-4.1.7)
* [REMOTE_ADDR](https://tools.ietf.org/html/rfc3875#section-4.1.8)
* [REMOTE_HOST](https://tools.ietf.org/html/rfc3875#section-4.1.9)
* [REMOTE_IDENT](https://tools.ietf.org/html/rfc3875#section-4.1.10)
* [REMOTE_USER](https://tools.ietf.org/html/rfc3875#section-4.1.11)
* [REQUEST_METHOD](https://tools.ietf.org/html/rfc3875#section-4.1.12)
* [SCRIPT_NAME](https://tools.ietf.org/html/rfc3875#section-4.1.13)
* [SERVER_NAME](https://tools.ietf.org/html/rfc3875#section-4.1.14)
* [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.
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/workbook/handling_request/form.md) | [Generating Responses](/workbook/generating_response/generating_response.md)

View File

@@ -0,0 +1,109 @@
note
description : "Basic Service that Read a Request, a "
date : "$Date$"
revision : "$Revision$"
EIS: "name=Browser detection using user agent","src=https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent", "protocol=url"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
set_service_option ("verbose", true)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
l_raw_data: STRING
l_page_response: STRING
l_rows: STRING
do
create l_page_response.make_from_string (html_template)
if req.path_info.same_string ("/") then
-- retrieve the user-agent
if attached req.http_user_agent as l_user_agent then
l_page_response.replace_substring_all ("$user_agent", l_user_agent)
l_page_response.replace_substring_all ("$browser", get_browser_name (l_user_agent))
else
l_page_response.replace_substring_all ("$user_agent", "[]")
l_page_response.replace_substring_all ("$browser", "Unknown, the user-agent was not present.")
end
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>)
res.put_string (l_page_response)
end
end
feature -- Browser utility
get_browser_name (a_user_agent: READABLE_STRING_8):READABLE_STRING_32
-- Must contain Must not contain
-- Firefox Firefox/xyz Seamonkey/xyz
-- Seamonkey Seamonkey/xyz
-- Chrome Chrome/xyz Chromium/xyz
-- Chromium Chromium/xyz
-- Safari Safari/xyz Chrome/xyz
-- Chromium/xyz
-- Opera OPR/xyz [1]
-- Opera/xyz [2]
-- Internet Explorer ;MSIE xyz; Internet Explorer doesn't put its name in the BrowserName/VersionNumber format
do
if
a_user_agent.has_substring ("Firefox") and then
not a_user_agent.has_substring ("Seamonkey")
then
Result := "Firefox"
elseif a_user_agent.has_substring ("Seamonkey") then
Result := "Seamonkey"
elseif a_user_agent.has_substring ("Chrome") and then not a_user_agent.has_substring ("Chromium")then
Result := "Chrome"
elseif a_user_agent.has_substring ("Chromium") then
Result := "Chromiun"
elseif a_user_agent.has_substring ("Safari") and then not (a_user_agent.has_substring ("Chrome") or else a_user_agent.has_substring ("Chromium")) then
Result := "Safari"
elseif a_user_agent.has_substring ("OPR") or else a_user_agent.has_substring ("Opera") then
Result := "Opera"
elseif a_user_agent.has_substring ("MSIE") or else a_user_agent.has_substring ("Trident")then
Result := "Internet Explorer"
else
Result := "Unknown"
end
end
html_template: STRING = "[
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>EWF service example: Showing Browser Dectection Using User-Agent</h1> <br>
<strong>User Agent:</strong> $user_agent <br>
<h2>Enjoy using $browser </h2>
</body>
</html>
]"
end

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="browsers" library_target="browsers">
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="browsers_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="browsers" location=".\" recursive="true"/>
</target>
<target name="browsers_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="browsers" location=".\" recursive="true"/>
</target>
<target name="browsers_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="browsers" location=".\" recursive="true"/>
</target>
<target name="browsers" extends="browsers_nino">
</target>
</system>

View File

@@ -0,0 +1,315 @@
note
description : "Basic Service that shows the standard CGI variables"
date : "$Date$"
revision : "$Revision$"
EIS: "name=CGI specification","src=(https://tools.ietf.org/html/rfc3875", "protocol=url"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
set_service_option ("verbose", true)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
l_raw_data: STRING
l_page_response: STRING
l_rows: STRING
do
create l_page_response.make_from_string (html_template)
if req.path_info.same_string ("/") then
-- HTTP method
l_page_response.replace_substring_all ("$http_method", req.request_method)
-- URI
l_page_response.replace_substring_all ("$uri", req.path_info)
-- Protocol
l_page_response.replace_substring_all ("$protocol", req.server_protocol)
-- Fill the table rows with CGI standard variables
create l_rows.make_empty
-- Auth_type
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("AUTH_TYPE")
l_rows.append ("</td>")
l_rows.append ("<td>")
if attached req.auth_type as l_type then
l_rows.append (l_type)
else
l_rows.append ("Not present")
end
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Content length
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("CONTENT_LENGTH")
l_rows.append ("</td>")
l_rows.append ("<td>")
if attached req.content_length as l_content_length then
l_rows.append (l_content_length)
else
l_rows.append ("Not present")
end
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Content length
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("CONTENT_TYPE")
l_rows.append ("</td>")
l_rows.append ("<td>")
if attached req.content_type as l_content_type then
l_rows.append (l_content_type.string)
else
l_rows.append ("Not present")
end
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Gateway interface
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("GATEWAY_INTERFACE")
l_rows.append ("</td>")
l_rows.append ("<td>")
if attached req.gateway_interface as l_gateway_interface then
l_rows.append (l_gateway_interface)
else
l_rows.append ("Not present")
end
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Path info
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("PATH_INFO")
l_rows.append ("</td>")
l_rows.append ("<td>")
if attached req.path_info as l_path_info then
l_rows.append (l_path_info)
else
l_rows.append ("Not present")
end
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Path translated
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("PATH_TRANSLATED")
l_rows.append ("</td>")
l_rows.append ("<td>")
if attached req.path_translated as l_path_translated then
l_rows.append (l_path_translated)
else
l_rows.append ("Not present")
end
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Query string
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("QUERY_STRING")
l_rows.append ("</td>")
l_rows.append ("<td>")
if attached req.query_string as l_query_string then
l_rows.append (l_query_string)
else
l_rows.append ("Not present")
end
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Remote addr
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("REMOTE_ADDR")
l_rows.append ("</td>")
l_rows.append ("<td>")
l_rows.append (req.remote_addr)
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Remote host
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("REMOTE_HOST")
l_rows.append ("</td>")
l_rows.append ("<td>")
if attached req.remote_host as l_remote_host then
l_rows.append (l_remote_host)
else
l_rows.append ("Not present")
end
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Remote ident
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("REMOTE_IDENT")
l_rows.append ("</td>")
l_rows.append ("<td>")
if attached req.remote_ident as l_remote_ident then
l_rows.append (l_remote_ident)
else
l_rows.append ("Not present")
end
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Remote user
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("REMOTE_USER")
l_rows.append ("</td>")
l_rows.append ("<td>")
if attached req.remote_user as l_remote_user then
l_rows.append (l_remote_user)
else
l_rows.append ("Not present")
end
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Request method
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("REQUEST_METHOD")
l_rows.append ("</td>")
l_rows.append ("<td>")
l_rows.append (req.request_method)
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Script name
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("SCRIPT_NAME")
l_rows.append ("</td>")
l_rows.append ("<td>")
l_rows.append (req.script_name)
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Server name
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("SERVER_NAME")
l_rows.append ("</td>")
l_rows.append ("<td>")
l_rows.append (req.server_name)
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Server protocol
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("SERVER_PROTOCOL")
l_rows.append ("</td>")
l_rows.append ("<td>")
l_rows.append (req.server_protocol)
l_rows.append ("</td>")
l_rows.append ("</tr>")
-- Server software
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append ("SERVER_SOFTWARE")
l_rows.append ("</td>")
l_rows.append ("<td>")
l_rows.append (req.server_software)
l_rows.append ("</td>")
l_rows.append ("</tr>")
l_page_response.replace_substring_all ("$rows", l_rows)
-- Reading the raw header
if attached req.raw_header_data as l_raw_header then
l_page_response.replace_substring_all ("$raw_header", l_raw_header)
end
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>)
res.put_string (l_page_response)
end
end
html_template: STRING = "[
<!DOCTYPE html>
<html>
<head>
<style>
thead {color:green;}
tbody {color:blue;}
table, th, td {
border: 1px solid black;
}
</style>
</head>
<body>
<h1>EWF service example: Showing Standard CGI Variables</h1>
<strong>HTTP METHOD:</strong>$http_method<br>
<strong>URI:</strong>$uri<br>
<strong>PROTOCOL:</strong>$protocol<br>
<br>
<table>
<thead>
<tr>
<th>CGI Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
$rows
</tbody>
</table>
<h2>Raw header</h2>
$raw_header
</body>
</html>
]"
end

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="cgi_variables" library_target="cgi_variables">
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="cgi_variables_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="cgi_variables" location=".\" recursive="true"/>
</target>
<target name="cgi_variables_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="cgi_variables" location=".\" recursive="true"/>
</target>
<target name="cgi_variables_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="cgi_variables" location=".\" recursive="true"/>
</target>
<target name="cgi_variables" extends="cgi_variables_nino">
</target>
</system>

View File

@@ -0,0 +1,117 @@
note
description : "Basic Service that Read Request Headers"
date : "$Date$"
revision : "$Revision$"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
set_service_option ("verbose", true)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
l_raw_data: STRING
l_page_response: STRING
l_rows: STRING
do
create l_page_response.make_from_string (html_template)
if req.path_info.same_string ("/") then
-- HTTP method
l_page_response.replace_substring_all ("$http_method", req.request_method)
-- URI
l_page_response.replace_substring_all ("$uri", req.path_info)
-- Protocol
l_page_response.replace_substring_all ("$protocol", req.server_protocol)
-- Fill the table rows with HTTP Headers
create l_rows.make_empty
across req.meta_variables as ic loop
if ic.item.name.starts_with ("HTTP_") then
l_rows.append ("<tr>")
l_rows.append ("<td>")
l_rows.append (ic.item.name)
l_rows.append ("</td>")
l_rows.append ("<td>")
l_rows.append (ic.item.value)
l_rows.append ("</td>")
l_rows.append ("</tr>")
end
end
l_page_response.replace_substring_all ("$rows", l_rows)
-- Reading the raw header
if attached req.raw_header_data as l_raw_header then
l_page_response.replace_substring_all ("$raw_header", l_raw_header)
end
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_page_response.count.out]>>)
res.put_string (l_page_response)
end
end
html_template: STRING = "[
<!DOCTYPE html>
<html>
<head>
<style>
thead {color:green;}
tbody {color:blue;}
table, th, td {
border: 1px solid black;
}
</style>
</head>
<body>
<h1>EWF service example: Showing Request Headers</h1>
<strong>HTTP METHOD:</strong>$http_method<br>
<strong>URI:</strong>$uri<br>
<strong>PROTOCOL:</strong>$protocol<br>
<strong>REQUEST TIME:</strong>$time<br>
<br>
<table>
<thead>
<tr>
<th>Header Name</th>
<th>Header Value</th>
</tr>
</thead>
<tbody>
$rows
</tbody>
</table>
<h2>Raw header</h2>
$raw_header
</body>
</html>
]"
end

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="header_fields" library_target="header_fields">
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="header_fields_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="header_fields" location=".\" recursive="true"/>
</target>
<target name="header_fields_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="header_fields" location=".\" recursive="true"/>
</target>
<target name="header_fields_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="header_fields" location=".\" recursive="true"/>
</target>
<target name="header_fields" extends="header_fields_nino">
</target>
</system>

View File

@@ -0,0 +1,69 @@
note
description : "Basic Service that show how to Upload a file"
date : "$Date$"
revision : "$Revision$"
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the incomming request
local
file: WSF_FILE_RESPONSE
l_answer: STRING
do
if req.is_get_request_method then
if req.path_info.same_string ("/") then
create file.make_html ("upload.html")
res.send (file)
else
-- Here we should handle unexpected errors.
end
elseif req.is_post_request_method then
if req.path_info.same_string ("/upload") then
-- Check if we have an uploaded file
if req.has_uploaded_file then
-- iterate over all the uploaded files
create l_answer.make_from_string ("<h1>Uploaded File/s</h1><br>")
across req.uploaded_files as ic loop
l_answer.append ("<strong>FileName:</strong>")
l_answer.append (ic.item.filename)
l_answer.append ("<br><strong>Size:</strong>")
l_answer.append (ic.item.size.out)
l_answer.append ("<br>")
end
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-type","text/html"],["Content-lenght", l_answer.count.out]>>)
res.put_string (l_answer)
else
-- Here we should handle unexpected errors.
create l_answer.make_from_string ("<strong>No uploaded files</strong><br>")
create l_answer.append ("Back to <a href='/'>Home</a>")
res.put_header ({HTTP_STATUS_CODE}.bad_request, <<["Content-type","text/html"],["Content-lenght", l_answer.count.out]>>)
res.put_string (l_answer)
end
else
-- Handle error
end
end
end
end

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="upload" library_target="upload">
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="$ISE_LIBRARY\contrib\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\wsf-safe.ecf"/>
</target>
<target name="upload_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_nino" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\nino-safe.ecf"/>
<cluster name="upload" location=".\" recursive="true"/>
</target>
<target name="upload_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_cgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\cgi-safe.ecf"/>
<cluster name="upload" location=".\" recursive="true"/>
</target>
<target name="upload_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="default_libfcgi" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\wsf\default\libfcgi-safe.ecf"/>
<cluster name="upload" location=".\" recursive="true"/>
</target>
<target name="upload" extends="upload_nino">
</target>
</system>

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>EWF Handling Client Request: File Upload Example</title>
</head>
<body>
<h1> EWF Handling Client Request: File Upload Example</h1>
<form action="/upload" enctype="multipart/form-data" method="POST">
<fieldset>
<legend>Upload file/s</legend>
<div>
<label>File
<input name="file-name[]" type="file" multiple>
</label>
<fieldset>
<div>
<button type=submit>Send</button>
</div>
</fieldset>
</form>
</body>
</html>

13
doc/workbook/readme.md Normal file
View File

@@ -0,0 +1,13 @@
Introduction
Basic Concepts
Generating Plain Text
Generation HTML
Handling Client Request:
Form Data
Request Heders
Query Parameters.

38
doc/workbook/workbook.md Normal file
View File

@@ -0,0 +1,38 @@
# EWF Workbook
##### Table of Contents
* [EWF Core](#core)
* [EWF Introduction](#introduction)
* [Handling Requests: Form/Query Parameter](#form_query_parameters)
* [Handling Requests: Header Fields](#header_fields)
* [Generating Responses](/workbook/generating_response/generating_response.md)
* [Handling Cookies](/workbook/handling_cookies/handling_cookies.md)
*
<a name="core"></a>
# EWF Core
Before reading (or walking throught) the workbook, to get a quick overview of EWF, it is recommended to read the following articles:
* [Getting Started with EWF](http://eiffelwebframework.github.io/EWF/getting-started/)
* [EWF Documentation](http://eiffelwebframework.github.io/EWF/wiki/Documentation/)
* [EWF Application Lifecyle](https://github.com/EiffelWebFramework/ewf_examples/wiki/Application-Lifecycle)
<a name="introduction"></a>
## Introduction
[Basic Concepts] (/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).
<a name="header_fields"></a>
## Handling Requests: Header Fields
[Handling Requests: Header Fields](/workbook/handling_request/headers.md).
<a name="header_fields"></a>
## Generating Response
[Generating Responses](/workbook/generating_response/generating_response.md)
## Handling Cookies
[Handling Cookies](/workbook/handling_cookies/handling_cookies.md)

View File

@@ -8,23 +8,11 @@ class
inherit
WSF_ROUTED_SERVICE
rename
execute as execute_router
end
WSF_FILTERED_SERVICE
WSF_DEFAULT_SERVICE
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
redefine
initialize
end
WSF_FILTER
rename
execute as execute_router
end
create
make_and_launch
@@ -33,75 +21,8 @@ feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
initialize_router
initialize_filter
Precursor
set_service_option ("port", 7070)
end
feature -- Router and Filter
create_filter
-- Create `filter'
local
f, l_filter: detachable WSF_FILTER
do
l_filter := Void
-- Maintenance
create {WSF_MAINTENANCE_FILTER} f
f.set_next (l_filter)
l_filter := f
-- Logging
create {WSF_LOGGING_FILTER} f
f.set_next (l_filter)
l_filter := f
filter := l_filter
end
setup_filter
-- Setup `filter'
local
f: WSF_FILTER
do
from
f := filter
until
not attached f.next as l_next
loop
f := l_next
end
f.set_next (Current)
end
setup_router
do
map_agent_uri ("/", agent execute_hello, Void)
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
-- this way, it handles the caching and so on
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
end
feature -- Helper: mapping
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
do
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
end
feature -- Execution
execute_hello (request: WSF_REQUEST; response: WSF_RESPONSE)
local
page: EMPTY_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (request, response)
page.execute
end
end

View File

@@ -0,0 +1,60 @@
note
description: "simple application root class"
date: "$Date$"
revision: "$Revision$"
class
APPLICATION_EXECUTION
inherit
WSF_FILTERED_ROUTED_EXECUTION
create
make
feature -- Router and Filter
create_filter
-- Create `filter'
do
-- Maintenance
create {WSF_MAINTENANCE_FILTER} filter
end
setup_filter
-- Setup `filter'
do
append_filters (<<create {WSF_LOGGING_FILTER}>>)
end
setup_router
do
map_agent_uri ("/", agent execute_hello, Void)
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
-- this way, it handles the caching and so on
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
end
feature -- Helper: mapping
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
do
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
end
feature -- Execution
execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE)
local
page: EMPTY_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (req, res)
page.execute
end
end

View File

@@ -8,23 +8,11 @@ class
inherit
WSF_ROUTED_SERVICE
rename
execute as execute_router
end
WSF_FILTERED_SERVICE
WSF_DEFAULT_SERVICE
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
redefine
initialize
end
WSF_FILTER
rename
execute as execute_router
end
create
make_and_launch
@@ -33,75 +21,8 @@ feature {NONE} -- Initialization
initialize
-- Initialize current service.
do
initialize_router
initialize_filter
Precursor
set_service_option ("port", 7070)
end
feature -- Router and Filter
create_filter
-- Create `filter'
local
f, l_filter: detachable WSF_FILTER
do
l_filter := Void
-- Maintenance
create {WSF_MAINTENANCE_FILTER} f
f.set_next (l_filter)
l_filter := f
-- Logging
create {WSF_LOGGING_FILTER} f
f.set_next (l_filter)
l_filter := f
filter := l_filter
end
setup_filter
-- Setup `filter'
local
f: WSF_FILTER
do
from
f := filter
until
not attached f.next as l_next
loop
f := l_next
end
f.set_next (Current)
end
setup_router
do
map_agent_uri ("/", agent execute_hello, Void)
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
-- this way, it handles the caching and so on
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
end
feature -- Helper: mapping
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
do
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
end
feature -- Execution
execute_hello (request: WSF_REQUEST; response: WSF_RESPONSE)
local
page: EMPTY_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (request, response)
page.execute
end
end

View File

@@ -0,0 +1,60 @@
note
description: "simple application root class"
date: "$Date$"
revision: "$Revision$"
class
APPLICATION_EXECUTION
inherit
WSF_FILTERED_ROUTED_EXECUTION
create
make
feature -- Router and Filter
create_filter
-- Create `filter'
do
-- Maintenance
create {WSF_MAINTENANCE_FILTER} filter
end
setup_filter
-- Setup `filter'
do
append_filters (<< create {WSF_LOGGING_FILTER} >>)
end
setup_router
do
map_agent_uri ("/", agent execute_hello, Void)
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
-- this way, it handles the caching and so on
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
end
feature -- Helper: mapping
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
do
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
end
feature -- Execution
execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE)
local
page: EMPTY_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (req, res)
page.execute
end
end

View File

@@ -8,168 +8,22 @@ class
inherit
WSF_ROUTED_SERVICE
rename
execute as execute_router
end
WSF_FILTERED_SERVICE
WSF_DEFAULT_SERVICE
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
redefine
initialize
end
WSF_FILTER
rename
execute as execute_router
end
create
make_and_launch
feature {NONE} -- Initialization
-- tt
-- local
-- lst: ARRAYED_LIST [READABLE_STRING_GENERAL]
-- do
-- create lst.make (3)
-- lst.compare_objects
-- lst.extend ({STRING_32} "abc")
-- if lst.has ("abc") then
-- print ("found%N")
-- end
-- end
initialize
-- Initialize current service.
do
-- tt
initialize_router
initialize_filter
Precursor
set_service_option ("port", 9090)
end
feature -- Router and Filter
create_filter
-- Create `filter'
local
f, l_filter: detachable WSF_FILTER
do
l_filter := Void
-- Maintenance
create {WSF_MAINTENANCE_FILTER} f
f.set_next (l_filter)
l_filter := f
-- Logging
create {WSF_LOGGING_FILTER} f
f.set_next (l_filter)
l_filter := f
filter := l_filter
end
setup_filter
-- Setup `filter'
local
f: WSF_FILTER
do
from
f := filter
until
not attached f.next as l_next
loop
f := l_next
end
f.set_next (Current)
end
setup_router
do
map_agent_uri ("/", agent execute_hello, Void)
map_agent_uri ("/grid", agent grid_demo, Void)
map_agent_uri ("/repeater", agent repeater_demo, Void)
map_agent_uri ("/slider", agent slider_demo, Void)
map_agent_uri ("/upload", agent upload_demo, Void)
map_agent_uri ("/codeview", agent codeview, Void)
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
-- this way, it handles the caching and so on
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
end
feature -- Helper: mapping
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
do
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
end
feature -- Execution
execute_hello (request: WSF_REQUEST; response: WSF_RESPONSE)
local
page: SAMPLE_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (request, response)
page.execute
end
grid_demo (request: WSF_REQUEST; response: WSF_RESPONSE)
local
page: GRID_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (request, response)
page.execute
end
repeater_demo (request: WSF_REQUEST; response: WSF_RESPONSE)
local
page: REPEATER_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (request, response)
page.execute
end
slider_demo (request: WSF_REQUEST; response: WSF_RESPONSE)
local
page: SLIDER_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (request, response)
page.execute
end
upload_demo (request: WSF_REQUEST; response: WSF_RESPONSE)
local
page: UPLOAD_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (request, response)
page.execute
end
codeview (request: WSF_REQUEST; response: WSF_RESPONSE)
local
page: CODEVIEW_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (request, response)
page.execute
end
end

View File

@@ -0,0 +1,113 @@
note
description: "Summary description for {APPLICATION_EXECUTION}."
date: "$Date$"
revision: "$Revision$"
class
APPLICATION_EXECUTION
inherit
WSF_FILTERED_ROUTED_EXECUTION
create
make
feature -- Router and Filter
create_filter
-- Create `filter'
do
-- Maintenance
create {WSF_MAINTENANCE_FILTER} filter
end
setup_filter
-- Setup `filter'
do
append_filters (<<create {WSF_LOGGING_FILTER}>>)
end
setup_router
do
map_agent_uri ("/", agent execute_hello, Void)
map_agent_uri ("/grid", agent grid_demo, Void)
map_agent_uri ("/repeater", agent repeater_demo, Void)
map_agent_uri ("/slider", agent slider_demo, Void)
map_agent_uri ("/upload", agent upload_demo, Void)
map_agent_uri ("/codeview", agent codeview, Void)
-- NOTE: you could put all those files in a specific folder, and use WSF_FILE_SYSTEM_HANDLER with "/"
-- this way, it handles the caching and so on
router.handle_with_request_methods ("/assets", create {WSF_FILE_SYSTEM_HANDLER}.make_hidden ("assets"), router.methods_GET)
end
feature -- Helper: mapping
map_agent_uri (a_uri: READABLE_STRING_8; a_action: like {WSF_URI_AGENT_HANDLER}.action; rqst_methods: detachable WSF_REQUEST_METHODS)
do
router.map_with_request_methods (create {WSF_URI_MAPPING}.make (a_uri, create {WSF_URI_AGENT_HANDLER}.make (a_action)), rqst_methods)
end
feature -- Execution
execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE)
local
page: SAMPLE_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (req, res)
page.execute
end
grid_demo (req: WSF_REQUEST; res: WSF_RESPONSE)
local
page: GRID_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (req, res)
page.execute
end
repeater_demo (req: WSF_REQUEST; res: WSF_RESPONSE)
local
page: REPEATER_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (req, res)
page.execute
end
slider_demo (req: WSF_REQUEST; res: WSF_RESPONSE)
local
page: SLIDER_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (req, res)
page.execute
end
upload_demo (req: WSF_REQUEST; res: WSF_RESPONSE)
local
page: UPLOAD_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (req, res)
page.execute
end
codeview (req: WSF_REQUEST; res: WSF_RESPONSE)
local
page: CODEVIEW_PAGE
do
-- To send a response we need to setup, the status code and
-- the response headers.
create page.make (req, res)
page.execute
end
end

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {CONTACT_AUTOCOMPLETION}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {FLAG_AUTOCOMPLETION}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {GOOGLE_AUTOCOMPLETION}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {BASE_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {CODEVIEW_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {GOOGLE_NEWS}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {GOOGLE_NEWS_DATASOURCE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {GOOGLE_NEWS_REPEATER}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {GRID_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {OWN_VALIDATOR}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {INCREASING_PROGRESSSOURCE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {REPEATER_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {SAMPLE_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {SLIDER_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {UPLOAD_PAGE}."
author: ""
date: "$Date$"
revision: "$Revision$"

View File

@@ -18,12 +18,21 @@
</target>
<target name="debug_any" extends="common">
<root class="EWF_DEBUG_SERVER" feature="make_and_launch"/>
<setting name="concurrency" value="scoop"/>
<library name="cgi" location="..\..\library\server\wsf\connector\cgi-safe.ecf" readonly="false"/>
<library name="libfcgi" location="..\..\library\server\wsf\connector\libfcgi-safe.ecf"/>
<library name="nino" location="..\..\library\server\wsf\connector\nino-safe.ecf"/>
<library name="libfcgi" location="..\..\library\server\wsf\connector\libfcgi-safe.ecf" readonly="false"/>
<library name="nino" location="..\..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/>
<library name="standalone" location="..\..\library\server\wsf\connector\standalone-safe.ecf" readonly="false"/>
<cluster name="launcher" location=".\launcher\any\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="debug_standalone" extends="common">
<root class="EWF_DEBUG_SERVER" feature="make_and_launch"/>
<setting name="concurrency" value="scoop"/>
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false"/>
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
<target name="debug_nino" extends="common">
<root class="EWF_DEBUG_SERVER" feature="make_and_launch"/>
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf"/>
@@ -32,7 +41,7 @@
</target>
<target name="debug_cgi" extends="common">
<root class="EWF_DEBUG_SERVER" feature="make_and_launch"/>
<library name="default_cgi" location="..\..\library\server\wsf\default\cgi-safe.ecf"/>
<library name="default_cgi" location="..\..\library\server\wsf\default\cgi-safe.ecf" readonly="false"/>
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>

View File

@@ -8,10 +8,10 @@ note
revision: "$Revision: 36 $"
class
APPLICATION_LAUNCHER
APPLICATION_LAUNCHER [G -> WSF_EXECUTION create make end]
inherit
APPLICATION_LAUNCHER_I
APPLICATION_LAUNCHER_I [G]
feature -- Custom

View File

@@ -10,24 +10,26 @@ note
revision: "$Revision: 36 $"
deferred class
APPLICATION_LAUNCHER_I
APPLICATION_LAUNCHER_I [G -> WSF_EXECUTION create make end]
inherit
SHARED_EXECUTION_ENVIRONMENT
feature -- Execution
launch (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
nature: like launcher_nature
do
nature := launcher_nature
if nature = Void or else nature = nature_nino then
launch_nino (a_service, opts)
if nature = Void or else nature = nature_standalone then
launch_standalone (opts)
elseif nature = nature_nino then
launch_nino (opts)
elseif nature = nature_cgi then
launch_cgi (a_service, opts)
launch_cgi (opts)
elseif nature = nature_libfcgi then
launch_libfcgi (a_service, opts)
launch_libfcgi (opts)
else
-- bye bye
(create {EXCEPTIONS}).die (-1)
@@ -43,14 +45,16 @@ feature {NONE} -- Access
--| and we could use WSF_DEFAULT_SERVICE_LAUNCHER to configure this at compilation time.
local
p: PATH
l_entry_name: READABLE_STRING_32
ext: detachable READABLE_STRING_32
do
create p.make_from_string (execution_environment.arguments.command_name)
if attached p.entry as l_entry then
ext := l_entry.extension
ext := l_entry.extension
end
if ext /= Void then
if ext.same_string (nature_standalone) then
Result := nature_standalone
end
if ext.same_string (nature_nino) then
Result := nature_nino
end
@@ -61,39 +65,51 @@ feature {NONE} -- Access
Result := nature_libfcgi
end
end
Result := nature_standalone
end
feature {NONE} -- nino
nature_standalone: STRING = "standalone"
launch_standalone (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_STANDALONE_SERVICE_LAUNCHER [G]
do
create launcher.make_and_launch (opts)
end
feature {NONE} -- nino
nature_nino: STRING = "nino"
launch_nino (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
launch_nino (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_NINO_SERVICE_LAUNCHER
launcher: WSF_NINO_SERVICE_LAUNCHER [G]
do
create launcher.make_and_launch (a_service, opts)
create launcher.make_and_launch (opts)
end
feature {NONE} -- cgi
nature_cgi: STRING = "cgi"
launch_cgi (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
launch_cgi (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_CGI_SERVICE_LAUNCHER
launcher: WSF_CGI_SERVICE_LAUNCHER [G]
do
create launcher.make_and_launch (a_service, opts)
create launcher.make_and_launch (opts)
end
feature {NONE} -- libfcgi
nature_libfcgi: STRING = "libfcgi"
launch_libfcgi (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
launch_libfcgi (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_LIBFCGI_SERVICE_LAUNCHER
launcher: WSF_LIBFCGI_SERVICE_LAUNCHER [G]
do
create launcher.make_and_launch (a_service, opts)
create launcher.make_and_launch (opts)
end

View File

@@ -8,10 +8,10 @@ note
revision: "$Revision: 36 $"
class
APPLICATION_LAUNCHER
APPLICATION_LAUNCHER [G -> WSF_EXECUTION create make end]
inherit
APPLICATION_LAUNCHER_I
APPLICATION_LAUNCHER_I [G]
feature -- Custom

View File

@@ -10,15 +10,15 @@ note
revision: "$Revision: 36 $"
deferred class
APPLICATION_LAUNCHER_I
APPLICATION_LAUNCHER_I [G -> WSF_EXECUTION create make end]
feature -- Execution
launch (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_SERVICE_LAUNCHER
launcher: WSF_SERVICE_LAUNCHER [G]
do
create {WSF_DEFAULT_SERVICE_LAUNCHER} launcher.make_and_launch (a_service, opts)
create {WSF_DEFAULT_SERVICE_LAUNCHER [G]} launcher.make_and_launch (opts)
end
end

View File

@@ -0,0 +1,27 @@
note
description: "Summary description for {EWF_DEBUG_EXECUTION}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
EWF_DEBUG_EXECUTION
inherit
WSF_EXECUTION
create
make
feature -- Execution
execute
local
dbg: WSF_DEBUG_HANDLER
do
response.put_error ("DEBUG uri=" + request.request_uri + "%N")
create dbg.make
dbg.execute_starts_with ("", request, response)
end
end

View File

@@ -14,7 +14,7 @@ inherit
initialize
end
APPLICATION_LAUNCHER
APPLICATION_LAUNCHER [EWF_DEBUG_EXECUTION]
create
make_and_launch
@@ -30,14 +30,14 @@ feature {NONE} -- Initialization
-- set_service_option ("base", "/www-debug/debug_service.fcgi/")
end
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
local
dbg: WSF_DEBUG_HANDLER
do
res.put_error ("DEBUG" + req.request_uri + "%N")
create dbg.make
dbg.execute_starts_with ("", req, res)
end
-- execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- local
-- dbg: WSF_DEBUG_HANDLER
-- do
-- res.put_error ("OH NO uri=" + req.request_uri + "%N")
-- create dbg.make
-- dbg.execute_starts_with ("", req, res)
-- end
end

View File

@@ -7,17 +7,16 @@
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true"/>
</option>
<setting name="concurrency" value="thread"/>
<precompile name="vision2-pre" location="$ISE_PRECOMP\vision2-mt-safe.ecf"/>
<setting name="concurrency" value="scoop"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="ewsgi" location="..\..\library\server\ewsgi\ewsgi-safe.ecf"/>
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
<library name="vision2" location="$ISE_LIBRARY\library\vision2\vision2-safe.ecf"/>
<library name="web_browser" location="$ISE_LIBRARY\library\web_browser\web_browser-safe.ecf" readonly="false"/>
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
<library name="wsf_nino" location="..\..\library\server\wsf\connector\nino-safe.ecf"/>
<library name="wsf_nino_connector" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf"/>
<cluster name="src" location=".\src" recursive="true">
<library name="wsf_standalone" location="..\..\library\server\wsf\connector\standalone-safe.ecf"/>
<library name="wsf_standalone_connector" location="..\..\library\server\ewsgi\connectors\standalone\standalone-safe.ecf"/>
<cluster name="src" location=".\src\" recursive="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>

View File

@@ -0,0 +1,239 @@
note
description: "Summary description for {APP_EMBEDDED_WEB_EXECUTION}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
APP_EMBEDDED_WEB_EXECUTION
inherit
EMBEDDED_WEB_EXECUTION
redefine
initialize
end
create
make
feature {NONE} -- Initialization
initialize
do
Precursor
create request_exit_operation_actions
local_connection_restriction_enabled := True
end
feature -- Execution
request_exit_operation_actions: ACTION_SEQUENCE [TUPLE]
execute
-- Execute the request
-- See `request.input' for input stream
-- `request.meta_variables' for the CGI meta variable
-- and `response' for output buffer
local
router: WSF_ROUTER
sess: detachable WSF_ROUTER_SESSION
m: WSF_HTML_PAGE_RESPONSE
b: STRING
fs: WSF_FILE_SYSTEM_HANDLER
req: like request
do
req := request
create router.make (3)
router.handle ("/test/{var}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_test))
router.handle ("/env", create {WSF_URI_AGENT_HANDLER}.make (agent handle_env))
router.handle ("/exit", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_exit))
create fs.make_with_path ((create {EXECUTION_ENVIRONMENT}).current_working_path.extended ("files"))
router.handle ("/files", fs)
create sess
router.dispatch (req, response, sess)
if not sess.dispatched then
create m.make
create b.make_from_string ("<h1>Hello Eiffel desktop user</h1>")
b.append ("<li><a href=%"" + req.script_url ("/test/start") + "%">test</a></li>")
b.append ("<li><a href=%"" + req.script_url ("/env") + "%">env</a></li>")
b.append ("<li><a href=%"" + req.script_url ("/files") + "%">files</a></li>")
b.append ("<li><a href=%"" + req.script_url ("/exit") + "%">exit</a></li>")
m.set_body (b)
response.send (m)
end
end
handle_test (req: WSF_REQUEST; res: WSF_RESPONSE)
local
m: WSF_HTML_PAGE_RESPONSE
b: STRING
l_name: READABLE_STRING_32
do
if attached {WSF_STRING} req.item ("var") as p_name then
l_name := p_name.value
else
l_name := {STRING_32} "Embedded web service and web_browser in vision2 application"
end
create m.make
create b.make_from_string ("<h1>This is a test about "+ m.html_encoded_string (l_name) +"</h1>")
b.append ("<li><a href=%"" + req.script_url ("/") + "%">back to home</a></li>")
if l_name.is_case_insensitive_equal_general ("start") then
b.append ("<li><a href=%"" + req.script_url ("/test/js") + "%">test javascript+ajax</a></li>")
elseif l_name.is_case_insensitive_equal_general ("js") then
b.append ("[
<div id="myDiv"><h2>Let AJAX change this text</h2>
<button type="button" onclick="loadXMLDoc()">Change Content</button>
</div>
]")
m.add_javascript_content ("[
function loadXMLDoc()
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","/test/ajax.txt",true);
xmlhttp.send();
}
]")
elseif l_name.is_case_insensitive_equal_general ("ajax.txt") then
b := "This is AJAX response ... from " + req.absolute_script_url ("")
end
m.set_body (b)
res.send (m)
end
handle_env (req: WSF_REQUEST; res: WSF_RESPONSE)
local
s: STRING_8
p: WSF_PAGE_RESPONSE
v: STRING_8
do
create s.make (2048)
s.append ("**DEBUG**%N")
req.set_raw_input_data_recorded (True)
append_iterable_to ("Meta variables:", req.meta_variables, s)
s.append_character ('%N')
append_iterable_to ("Path parameters", req.path_parameters, s)
s.append_character ('%N')
append_iterable_to ("Query parameters", req.query_parameters, s)
s.append_character ('%N')
append_iterable_to ("Form parameters", req.form_parameters, s)
s.append_character ('%N')
if attached req.content_type as l_type then
s.append ("Content: type=" + l_type.debug_output)
s.append (" length=")
s.append_natural_64 (req.content_length_value)
s.append_character ('%N')
create v.make (req.content_length_value.to_integer_32)
req.read_input_data_into (v)
across
v.split ('%N') as v_cursor
loop
s.append (" |")
s.append (v_cursor.item)
s.append_character ('%N')
end
end
create p.make_with_body (s)
p.header.put_content_type_text_plain
res.send (p)
end
handle_exit (req: WSF_REQUEST; res: WSF_RESPONSE)
local
m: WSF_HTML_PAGE_RESPONSE
b: STRING
do
create m.make
create b.make_from_string ("<h1>Embedded server is about to shutdown</h1>")
b.append ("<li><a href=%"" + req.script_url ("/") + "%">back to home</a></li>")
b.append ("<li><a href=%"" + req.script_url ("/bye") + "%">Click to confirm exit operation</a></li>")
m.set_body (b)
res.send (m)
if attached {separate WGI_STANDALONE_CONNECTOR [WGI_EXECUTION]} req.wgi_connector as conn then
shutdown_server (conn)
end
request_exit_operation_actions.call (Void)
end
shutdown_server (conn: separate WGI_STANDALONE_CONNECTOR [WGI_EXECUTION])
do
conn.shutdown_server
end
feature {NONE} -- Implementation
append_iterable_to (a_title: READABLE_STRING_8; it: detachable ITERABLE [WSF_VALUE]; s: STRING_8)
local
n: INTEGER
t: READABLE_STRING_8
v: READABLE_STRING_8
do
s.append (a_title)
s.append_character (':')
if it /= Void then
across it as c loop
n := n + 1
end
if n = 0 then
s.append (" empty")
s.append_character ('%N')
else
s.append_character ('%N')
across
it as c
loop
s.append (" - ")
s.append (c.item.url_encoded_name)
t := c.item.generating_type
if t.same_string ("WSF_STRING") then
else
s.append_character (' ')
s.append_character ('{')
s.append (t)
s.append_character ('}')
end
s.append_character ('=')
v := c.item.string_representation.as_string_8
if v.has ('%N') then
s.append_character ('%N')
across
v.split ('%N') as v_cursor
loop
s.append (" |")
s.append (v_cursor.item)
s.append_character ('%N')
end
else
s.append (v)
s.append_character ('%N')
end
end
end
else
s.append (" none")
s.append_character ('%N')
end
end
end

View File

@@ -8,223 +8,11 @@ class
APP_EMBEDDED_WEB_SERVICE
inherit
EMBEDDED_WEB_SERVICE
redefine
make
end
EMBEDDED_WEB_SERVICE [APP_EMBEDDED_WEB_EXECUTION]
create
make
feature {NONE} -- Initialization
make
do
Precursor
create request_exit_operation_actions
local_connection_restriction_enabled := True
end
feature -- Execution
request_exit_operation_actions: ACTION_SEQUENCE [TUPLE]
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the request
-- See `req.input' for input stream
-- `req.meta_variables' for the CGI meta variable
-- and `res' for output buffer
local
router: WSF_ROUTER
sess: detachable WSF_ROUTER_SESSION
m: WSF_HTML_PAGE_RESPONSE
b: STRING
fs: WSF_FILE_SYSTEM_HANDLER
do
create router.make (3)
router.handle ("/test/{var}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_test))
router.handle ("/env", create {WSF_URI_AGENT_HANDLER}.make (agent handle_env))
router.handle ("/exit", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_exit))
create fs.make_with_path ((create {EXECUTION_ENVIRONMENT}).current_working_path.extended ("files"))
router.handle ("/files", fs)
create sess
router.dispatch (req, res, sess)
if not sess.dispatched then
create m.make
create b.make_from_string ("<h1>Hello Eiffel desktop user</h1>")
b.append ("<li><a href=%"" + req.script_url ("/test/start") + "%">test</a></li>")
b.append ("<li><a href=%"" + req.script_url ("/env") + "%">env</a></li>")
b.append ("<li><a href=%"" + req.script_url ("/files") + "%">files</a></li>")
b.append ("<li><a href=%"" + req.script_url ("/exit") + "%">exit</a></li>")
m.set_body (b)
res.send (m)
end
end
handle_test (req: WSF_REQUEST; res: WSF_RESPONSE)
local
m: WSF_HTML_PAGE_RESPONSE
b: STRING
l_name: READABLE_STRING_32
do
if attached {WSF_STRING} req.item ("var") as p_name then
l_name := p_name.value
else
l_name := {STRING_32} "Embedded web service and web_browser in vision2 application"
end
create m.make
create b.make_from_string ("<h1>This is a test about "+ m.html_encoded_string (l_name) +"</h1>")
b.append ("<li><a href=%"" + req.script_url ("/") + "%">back to home</a></li>")
if l_name.is_case_insensitive_equal_general ("start") then
b.append ("<li><a href=%"" + req.script_url ("/test/js") + "%">test javascript+ajax</a></li>")
elseif l_name.is_case_insensitive_equal_general ("js") then
b.append ("[
<div id="myDiv"><h2>Let AJAX change this text</h2>
<button type="button" onclick="loadXMLDoc()">Change Content</button>
</div>
]")
m.add_javascript_content ("[
function loadXMLDoc()
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","/test/ajax.txt",true);
xmlhttp.send();
}
]")
elseif l_name.is_case_insensitive_equal_general ("ajax.txt") then
b := "This is AJAX response ... from " + req.absolute_script_url ("")
end
m.set_body (b)
res.send (m)
end
handle_env (req: WSF_REQUEST; res: WSF_RESPONSE)
local
s: STRING_8
p: WSF_PAGE_RESPONSE
v: STRING_8
do
create s.make (2048)
s.append ("**DEBUG**%N")
req.set_raw_input_data_recorded (True)
append_iterable_to ("Meta variables:", req.meta_variables, s)
s.append_character ('%N')
append_iterable_to ("Path parameters", req.path_parameters, s)
s.append_character ('%N')
append_iterable_to ("Query parameters", req.query_parameters, s)
s.append_character ('%N')
append_iterable_to ("Form parameters", req.form_parameters, s)
s.append_character ('%N')
if attached req.content_type as l_type then
s.append ("Content: type=" + l_type.debug_output)
s.append (" length=")
s.append_natural_64 (req.content_length_value)
s.append_character ('%N')
create v.make (req.content_length_value.to_integer_32)
req.read_input_data_into (v)
across
v.split ('%N') as v_cursor
loop
s.append (" |")
s.append (v_cursor.item)
s.append_character ('%N')
end
end
create p.make_with_body (s)
p.header.put_content_type_text_plain
res.send (p)
end
handle_exit (req: WSF_REQUEST; res: WSF_RESPONSE)
local
m: WSF_HTML_PAGE_RESPONSE
b: STRING
do
create m.make
create b.make_from_string ("<h1>Embedded server is about to shutdown</h1>")
b.append ("<li><a href=%"" + req.script_url ("/") + "%">back to home</a></li>")
m.set_body (b)
res.send (m)
if attached {WGI_NINO_CONNECTOR} req.wgi_connector as nino then
nino.server.shutdown_server
end
request_exit_operation_actions.call (Void)
end
feature {NONE} -- Implementation
append_iterable_to (a_title: READABLE_STRING_8; it: detachable ITERABLE [WSF_VALUE]; s: STRING_8)
local
n: INTEGER
t: READABLE_STRING_8
v: READABLE_STRING_8
do
s.append (a_title)
s.append_character (':')
if it /= Void then
across it as c loop
n := n + 1
end
if n = 0 then
s.append (" empty")
s.append_character ('%N')
else
s.append_character ('%N')
across
it as c
loop
s.append (" - ")
s.append (c.item.url_encoded_name)
t := c.item.generating_type
if t.same_string ("WSF_STRING") then
else
s.append_character (' ')
s.append_character ('{')
s.append (t)
s.append_character ('}')
end
s.append_character ('=')
v := c.item.string_representation.as_string_8
if v.has ('%N') then
s.append_character ('%N')
across
v.split ('%N') as v_cursor
loop
s.append (" |")
s.append (v_cursor.item)
s.append_character ('%N')
end
else
s.append (v)
s.append_character ('%N')
end
end
end
else
s.append (" none")
s.append_character ('%N')
end
end
end

View File

@@ -24,18 +24,17 @@ feature {NONE} -- Initialization
-- then launch the application.
local
l_win: like main_window
l_embeded_services: APP_EMBEDDED_WEB_SERVICE
l_embedded_service: APP_EMBEDDED_WEB_SERVICE
do
default_create
create l_win.make
main_window := l_win
l_win.show
create l_embeded_services.make
l_embeded_services.set_port_number (0) -- Use first available port number
create l_embedded_service.make
l_embedded_service.set_port_number (0) -- Use first available port number
l_embeded_services.on_launched_actions.force (agent on_web_service_launched (l_win))
l_embeded_services.request_exit_operation_actions.force (agent on_quit)
l_embeded_services.launch
l_embedded_service.on_launched_actions.force (agent on_web_service_launched (l_win, l_embedded_service))
l_embedded_service.launch
launch
end
@@ -46,11 +45,44 @@ feature {NONE} -- Initialization
end
end
on_web_service_launched (a_win: attached like main_window)
on_web_service_launched (a_win: attached like main_window; s: APP_EMBEDDED_WEB_SERVICE)
do
add_idle_action_kamikaze (agent wait_for_termination (s, Void))
add_idle_action_kamikaze (agent a_win.open_link)
end
wait_for_termination (s: APP_EMBEDDED_WEB_SERVICE; a_timeout: detachable EV_TIMEOUT)
local
t: detachable EV_TIMEOUT
do
t := a_timeout
if t /= Void then
t.set_interval (0)
end
if
attached s.observer as obs and then
observer_has_terminaded (obs)
then
if t /= Void then
t.destroy
end
on_quit
else
if t = Void then
create t
t.actions.extend (agent wait_for_termination (s, t))
else
t.set_interval (1_000)
end
t.set_interval (1_000)
end
end
observer_has_terminaded (obs: separate WGI_STANDALONE_SERVER_OBSERVER): BOOLEAN
do
Result := obs.terminated
end
feature {NONE} -- Implementation
main_window: detachable MAIN_WINDOW

View File

@@ -0,0 +1,63 @@
note
description: "Summary description for {EMBEDDED_WEB_EXECUTION}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred class
EMBEDDED_WEB_EXECUTION
inherit
WSF_EXECUTION
rename
execute as execute_embedded
end
SHARED_EMBEDED_WEB_SERVICE_INFORMATION
feature {NONE} -- Execution
execute_embedded
-- Execute the request
-- See `request.input' for input stream
-- `request.meta_variables' for the CGI meta variable
-- and `response' for output buffer
local
filter: WSF_AGENT_FILTER
m: WSF_PAGE_RESPONSE
do
if local_connection_restriction_enabled then
if
attached request.remote_addr as l_remote_addr and then
l_remote_addr.is_case_insensitive_equal_general ("127.0.0.1")
then
execute
else
create m.make_with_body ("Only local connection is allowed")
m.set_status_code (403) -- Forbidden
response.send (m)
end
else
execute
end
end
execute
deferred
end
feature -- Status report
local_connection_restriction_enabled: BOOLEAN
-- Accept only local connection?
--| based on 127.0.0.1 IP
--| TO IMPROVE
feature -- Change
set_local_connection_restriction_enabled (b: BOOLEAN)
do
local_connection_restriction_enabled := b
end
end

View File

@@ -5,19 +5,10 @@ note
revision: "$Revision$"
deferred class
EMBEDDED_WEB_SERVICE
EMBEDDED_WEB_SERVICE [G -> EMBEDDED_WEB_EXECUTION create make end]
inherit
THREAD
rename
make as make_thread,
execute as execute_thread
end
WSF_SERVICE
rename
execute as execute_embedded
end
SHARED_EMBEDED_WEB_SERVICE_INFORMATION
@@ -25,90 +16,35 @@ feature -- Initialization
make
do
make_thread
create on_launched_actions
end
feature {NONE} -- Execution
feature -- Execution
execute_embedded (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the request
-- See `req.input' for input stream
-- `req.meta_variables' for the CGI meta variable
-- and `res' for output buffer
launch
local
filter: WSF_AGENT_FILTER
m: WSF_PAGE_RESPONSE
do
if local_connection_restriction_enabled then
if
attached req.remote_addr as l_remote_addr and then
l_remote_addr.is_case_insensitive_equal_general ("127.0.0.1")
then
execute (req, res)
else
create m.make_with_body ("Only local connection is allowed")
m.set_status_code (403) -- Forbidden
res.send (m)
end
else
execute (req, res)
end
end
execute_thread
local
nino: WSF_NINO_SERVICE_LAUNCHER
launcher: WSF_STANDALONE_SERVICE_LAUNCHER [G]
opts: WSF_SERVICE_LAUNCHER_OPTIONS
do
create opts.default_create
opts.set_verbose (True)
opts.set_option ("port", port_number)
create nino.make (Current, opts)
nino.on_launched_actions.force (agent on_launched)
nino.launch
create launcher.make (opts)
observer := launcher.connector.observer
launcher.on_launched_actions.force (agent on_launched)
launcher.launch
end
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the request
-- See `req.input' for input stream
-- `req.meta_variables' for the CGI meta variable
-- and `res' for output buffer
deferred
end
observer: detachable separate WGI_STANDALONE_SERVER_OBSERVER
on_launched (conn: WGI_CONNECTOR)
on_launched (conn: WGI_STANDALONE_CONNECTOR [G])
do
if attached {WGI_NINO_CONNECTOR} conn as nino then
set_port_number (nino.port)
end
set_port_number (conn.port)
on_launched_actions.call (Void)
end
feature -- Control
wait
-- Wait for server to be terminated.
do
join
end
feature -- Access
on_launched_actions: ACTION_SEQUENCE [TUPLE]
feature -- Status report
local_connection_restriction_enabled: BOOLEAN
-- Accept only local connection?
--| based on 127.0.0.1 IP
--| TO IMPROVE
feature -- Change
set_local_connection_restriction_enabled (b: BOOLEAN)
do
local_connection_restriction_enabled := b
end
end

View File

@@ -11,15 +11,25 @@ feature -- Access
port_number: INTEGER
do
Result := port_number_cell.item
Result := separate_port_number (port_number_cell)
end
set_port_number (a_port: like port_number)
do
port_number_cell.replace (a_port)
separate_set_port_number (port_number_cell, a_port)
end
port_number_cell: CELL [INTEGER]
separate_port_number (cl: like port_number_cell): like port_number
do
Result := cl.item
end
separate_set_port_number (cl: like port_number_cell; a_port: like port_number)
do
cl.replace (a_port)
end
port_number_cell: separate CELL [INTEGER]
once ("process")
create Result.put (0)
end

View File

@@ -1,30 +1,36 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-9-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-9-0 http://www.eiffel.com/developers/xml/configuration-1-9-0.xsd" name="filter" uuid="52FF4B77-0614-4D8B-9B96-C07EC852793E" library_target="filter">
<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="filter" uuid="52FF4B77-0614-4D8B-9B96-C07EC852793E" library_target="filter">
<target name="common">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/\.git$</exclude>
<exclude>/\.svn$</exclude>
</file_rule>
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="provisional">
<debug name="nino" enabled="true"/>
<assertions precondition="true" postcondition="true" invariant="true" supplier_precondition="true"/>
</option>
<setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf" readonly="true"/>
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf" readonly="true"/>
<library name="http" location="../../library/network/protocol/http/http-safe.ecf" readonly="true"/>
<library name="json" location="..\..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="true"/>
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf" readonly="true"/>
<library name="wsf_router_context" location="..\..\library\server\wsf\wsf_router_context-safe.ecf" readonly="true"/>
<library name="wsf_extension" location="..\..\library\server\wsf\wsf_extension-safe.ecf" readonly="true"/>
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf" readonly="true"/>
<library name="http_authorization" location="..\..\library\server\authentication\http_authorization\http_authorization-safe.ecf" readonly="true"/>
<library name="json" location="..\..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="true"/>
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf" readonly="true"/>
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
<library name="wsf_extension" location="..\..\library\server\wsf\wsf_extension-safe.ecf" readonly="true"/>
<library name="wsf_router_context" location="..\..\library\server\wsf\wsf_router_context-safe.ecf" readonly="true"/>
</target>
<target name="filter_nino" extends="common">
<root class="FILTER_SERVER" feature="make"/>
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf" readonly="true"/>
<cluster name="filter" location="src\" recursive="true"/>
</target>
<target name="filter_standalone" extends="common">
<root class="FILTER_SERVER" feature="make"/>
<setting name="concurrency" value="scoop"/>
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="true"/>
<cluster name="filter" location="src\" recursive="true"/>
</target>
<target name="filter_fcgi" extends="common">
<root class="FILTER_SERVER" feature="make"/>
<library name="default_libfcgi" location="..\..\library\server\wsf\default\libfcgi-safe.ecf"/>

View File

@@ -24,26 +24,33 @@ feature -- Initialization
feature -- Access
user_by_id (a_id: INTEGER): detachable USER
do
Result := users.item (a_id)
end
user_by_name (a_name: READABLE_STRING_GENERAL): detachable USER
do
across
users as c
until
Result /= Void
loop
if attached c.item as u and then a_name.same_string (u.name) then
Result := u
end
end
end
user (a_id: INTEGER; a_name: detachable READABLE_STRING_GENERAL): detachable USER
-- User with id `a_id' or name `a_name'.
require
a_id > 0 xor a_name /= Void
local
n: like {USER}.name
do
if a_id > 0 then
Result := users.item (a_id)
Result := user_by_id (a_id)
elseif a_name /= Void then
n := a_name.as_string_8
across
users as c
until
Result /= Void
loop
if attached c.item as u and then u.name.same_string (n) then
Result := u
end
end
Result := user_by_name (a_name)
end
ensure
Result /= Void implies ((a_id > 0 and then Result.id = a_id) xor (a_name /= Void and then Result.name.same_string_general (a_name)))
@@ -52,6 +59,6 @@ feature -- Access
users: HASH_TABLE [USER, INTEGER]
;note
copyright: "2011-2012, Olivier Ligot, Jocelyn Fiat and others"
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -48,18 +48,31 @@ feature {NONE} -- Implementation
-- Handle forbidden.
local
h: HTTP_HEADER
s: STRING
do
create h.make
h.put_content_type_text_plain
h.put_content_length (a_description.count)
h.put_current_date
h.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate, "Basic realm=%"User%"")
s := "Basic realm=%"For this demo, use any of: "
across
db_access.users as ic
loop
s.append_character ('(')
s.append (ic.item.name)
s.append_character (':')
s.append (ic.item.password)
s.append_character (')')
s.append_character (' ')
end
s.append_character ('"')
h.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate, s)
res.set_status_code ({HTTP_STATUS_CODE}.unauthorized)
res.put_header_text (h.string)
res.put_string (a_description)
end
note
copyright: "2011-2014, Olivier Ligot, Jocelyn Fiat and others"
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -8,18 +8,7 @@ class
FILTER_SERVER
inherit
ANY
WSF_DEFAULT_SERVICE
WSF_ROUTED_SERVICE
undefine
execute
end
WSF_FILTERED_SERVICE
SHARED_EJSON
WSF_DEFAULT_SERVICE [FILTER_SERVER_EXECUTION]
create
make
@@ -31,9 +20,6 @@ feature {NONE} -- Initialization
l_message: STRING
l_factory: INET_ADDRESS_FACTORY
do
initialize_router
initialize_filter
initialize_json
set_service_option ("port", port)
create l_message.make_empty
l_message.append_string ("Launching filter server at ")
@@ -46,60 +32,13 @@ feature {NONE} -- Initialization
make_and_launch
end
create_filter
-- Create `filter'
do
create {WSF_CORS_FILTER} filter
end
setup_filter
-- Setup `filter'
local
l_routing_filter: WSF_ROUTING_FILTER
l_logging_filter: WSF_LOGGING_FILTER
do
create l_routing_filter.make (router)
l_routing_filter.set_execute_default_action (agent execute_default)
filter.set_next (l_routing_filter)
create l_logging_filter
l_routing_filter.set_next (l_logging_filter)
end
setup_router
-- Setup `router'
local
l_options_filter: WSF_CORS_OPTIONS_FILTER
l_authentication_filter: AUTHENTICATION_FILTER
l_user_filter: USER_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_options_filter.make (router)
create l_authentication_filter
create l_user_filter
l_options_filter.set_next (l_authentication_filter)
l_authentication_filter.set_next (l_user_filter)
create l_methods
l_methods.enable_options
l_methods.enable_get
router.handle_with_request_methods ("/user/{userid}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent l_options_filter.execute), l_methods)
end
initialize_json
-- Initialize `json'.
do
json.add_converter (create {JSON_USER_CONVERTER}.make)
end
feature {NONE} -- Implementation
port: INTEGER = 9090
-- Port number
note
copyright: "2011-2014, Olivier Ligot, Jocelyn Fiat and others"
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -0,0 +1,82 @@
note
description : "Filter example."
author : "Olivier Ligot"
date : "$Date$"
revision : "$Revision$"
class
FILTER_SERVER_EXECUTION
inherit
WSF_FILTERED_ROUTED_EXECUTION
redefine
initialize
end
SHARED_EJSON
create
make
feature {NONE} -- Initialization
initialize
do
Precursor
initialize_json
end
create_filter
-- Create `filter'
do
create {WSF_CORS_FILTER} filter
end
setup_filter
-- Setup `filter'
local
l_logging_filter: WSF_LOGGING_FILTER
do
create l_logging_filter
filter.set_next (l_logging_filter)
end
setup_router
-- Setup `router'
local
l_options_filter: WSF_CORS_OPTIONS_FILTER
l_authentication_filter: AUTHENTICATION_FILTER
l_user_filter: USER_HANDLER
l_methods: WSF_REQUEST_METHODS
do
create l_options_filter.make (router)
create l_authentication_filter
create l_user_filter
l_options_filter.set_next (l_authentication_filter)
l_authentication_filter.set_next (l_user_filter)
create l_methods
l_methods.enable_options
l_methods.enable_get
router.handle_with_request_methods ("/user/{userid}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent l_options_filter.execute), l_methods)
end
initialize_json
-- Initialize `json'.
once
-- See SHARED_EJSON, and the once function per thread `json'.
json.add_converter (create {JSON_USER_CONVERTER}.make)
end
note
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -41,7 +41,7 @@ feature -- Basic operations
local
id : STRING
do
if attached req.orig_path_info as orig_path then
if attached req.path_info as orig_path then
id := get_user_id_from_path (orig_path)
if attached retrieve_user (id) as l_user then
if l_user ~ req.execution_variable ("user") then
@@ -86,12 +86,14 @@ feature {NONE} -- Implementation
retrieve_user (id: STRING) : detachable USER
-- Retrieve the user by id if it exist, in other case, Void
do
if id.is_integer and then Db_access.users.has (id.to_integer) then
Result := db_access.users.item (id.to_integer)
if id.is_integer then
Result := db_access.user_by_id (id.to_integer)
else
Result := db_access.user_by_name (id)
end
end
note
copyright: "2011-2013, Olivier Ligot, Jocelyn Fiat and others"
copyright: "2011-2015, Olivier Ligot, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
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-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="restbucks" uuid="2773FEAA-448F-410E-BEDE-9298C4749066" library_target="restbucks">
<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="restbucks" uuid="2773FEAA-448F-410E-BEDE-9298C4749066" library_target="restbucks">
<target name="restbucks_common">
<file_rule>
<exclude>/EIFGENs$</exclude>
@@ -8,16 +8,16 @@
</file_rule>
<option full_class_checking="false" void_safety="all">
</option>
<setting name="concurrency" value="thread"/>
<setting name="concurrency" value="scoop"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="connector_nino" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false">
<library name="connector_standalone" location="..\..\library\server\ewsgi\connectors\standalone\standalone-safe.ecf" readonly="false">
<option debug="true">
<debug name="nino" enabled="true"/>
<debug name="standalone" enabled="true"/>
</option>
</library>
<library name="conneg" location="..\..\library\network\protocol\content_negotiation\conneg-safe.ecf"/>
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf" readonly="false"/>
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf" readonly="false"/>
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false"/>
<library name="encoder" location="..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf" readonly="false"/>
<library name="json" location="..\..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
@@ -30,7 +30,7 @@
<target name="restbucks" extends="restbucks_common">
<root class="RESTBUCKS_SERVER" feature="make"/>
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="provisional">
<debug name="nino" enabled="true"/>
<debug name="standalone" enabled="true"/>
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<cluster name="src" location="src\" recursive="true">
@@ -42,7 +42,7 @@
<target name="policy_driven_restbucks" extends="restbucks_common">
<root class="RESTBUCKS_SERVER" feature="make"/>
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="provisional">
<debug name="nino" enabled="true"/>
<debug name="standalone" enabled="true"/>
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="wsf_policy_driven" location="..\..\library\server\wsf\wsf_policy_driven-safe.ecf" readonly="false"/>

View File

@@ -6,19 +6,7 @@ note
class RESTBUCKS_SERVER
inherit
WSF_ROUTED_SKELETON_SERVICE
undefine
requires_proxy
end
WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE
WSF_HANDLER_HELPER
WSF_DEFAULT_SERVICE
WSF_NO_PROXY_POLICY
WSF_DEFAULT_SERVICE [RESTBUCKS_SERVER_EXECUTION]
create
make
@@ -27,26 +15,12 @@ feature {NONE} -- Initialization
make
do
initialize_router
set_service_option ("port", 9090)
make_and_launch
end
setup_router
local
order_handler: ORDER_HANDLER
doc: WSF_ROUTER_SELF_DOCUMENTATION_HANDLER
do
create order_handler.make_with_router (router)
router.handle_with_request_methods ("/order", order_handler, router.methods_POST)
router.handle_with_request_methods ("/order/{orderid}", order_handler, router.methods_GET + router.methods_DELETE + router.methods_PUT)
create doc.make_hidden (router)
router.handle_with_request_methods ("/api/doc", doc, router.methods_GET)
end
note
copyright: "2011-2013, Javier Velilla and others"
copyright: "2011-2015, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -0,0 +1,57 @@
note
description : "REST Buck server"
date : "$Date$"
revision : "$Revision$"
class RESTBUCKS_SERVER_EXECUTION
inherit
WSF_ROUTED_SKELETON_EXECUTION
undefine
requires_proxy
redefine
initialize
end
WSF_ROUTED_URI_TEMPLATE_HELPER
WSF_HANDLER_HELPER
WSF_NO_PROXY_POLICY
create
make
feature {NONE} -- Initialization
initialize
do
Precursor
initialize_router
end
setup_router
local
order_handler: ORDER_HANDLER
doc: WSF_ROUTER_SELF_DOCUMENTATION_HANDLER
do
create order_handler.make_with_router (router)
router.handle_with_request_methods ("/order", order_handler, router.methods_POST)
router.handle_with_request_methods ("/order/{orderid}", order_handler, router.methods_GET + router.methods_DELETE + router.methods_PUT)
create doc.make_hidden (router)
router.handle_with_request_methods ("/api/doc", doc, router.methods_GET)
end
note
copyright: "2011-2015, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -7,7 +7,7 @@ class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
redefine
initialize
end
@@ -23,14 +23,6 @@ feature {NONE} -- Initialization
set_service_option ("port", 9090)
end
feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
do
-- To send a response we need to setup, the status code and
-- the response headers.
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/plain"], ["Content-Length", "11"]>>)
res.put_string ("Hello World")
end
end

View File

@@ -0,0 +1,34 @@
note
description : "simple application execution"
date : "$Date$"
revision : "$Revision$"
class
APPLICATION_EXECUTION
inherit
WSF_EXECUTION
create
make
feature -- Basic operations
execute
local
s: STRING
do
-- To send a response we need to setup, the status code and
-- the response headers.
s := "Hello World!"
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", s.count.out]>>)
response.set_status_code ({HTTP_STATUS_CODE}.ok)
response.header.put_content_type_text_html
response.header.put_content_length (s.count)
if attached request.http_connection as l_connection and then l_connection.is_case_insensitive_equal_general ("keep-alive") then
response.header.put_header_key_value ("Connection", "keep-alive")
end
response.put_string (s)
end
end

View File

@@ -1,21 +1,30 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="simple" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="simple">
<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="simple" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="simple">
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
</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>
<setting name="concurrency" value="scoop"/>
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf"/>
<cluster name="simple" location=".\" recursive="true"/>
</target>
<target name="simple_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<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_nino" location="..\..\library\server\wsf\default\nino-safe.ecf"/>
@@ -23,7 +32,7 @@
</target>
<target name="simple_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<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_cgi" location="..\..\library\server\wsf\default\cgi-safe.ecf"/>
@@ -31,12 +40,12 @@
</target>
<target name="simple_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<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_libfcgi" location="..\..\library\server\wsf\default\libfcgi-safe.ecf"/>
<cluster name="simple" location=".\" recursive="true"/>
</target>
<target name="simple" extends="simple_nino">
<target name="simple" extends="simple_standalone">
</target>
</system>

View File

@@ -0,0 +1,12 @@
<html>
<head>
<title>404 not found!</title>
</head>
<body>
<h1>404 not found!</h1>
This is a static html file served by EWF.
<img src="ewf.png"/>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,13 +1,13 @@
<html>
<head>
Eiffel REST services
<title>EWF simple_file example</title>
</head>
<body>
Welcome to the Eiffel REST services site, here you will find a lot of <br/>
resources about REST and our solution
<h1>EWF simple_file example</h1>
<p>This is a static html file served by EWF.</p>
<p>Try to <a href="nowhere.html">get lost</a>.</p>
<a href="ewf.png"><img src="ewf.png"/></a>
</body>
</html>
</html>

View File

@@ -7,18 +7,20 @@ class
SERVICE_FILE
inherit
WSF_DEFAULT_SERVICE
WSF_DEFAULT_SERVICE [SERVICE_FILE_EXECUTION]
redefine
initialize
end
create
make_and_launch
feature {NONE} -- Initialization
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
local
f: WSF_FILE_RESPONSE
initialize
do
create f.make_html ("home.html")
res.send (f)
Precursor
set_service_option ("port", 9090)
end
end

View File

@@ -1,14 +1,15 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-9-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-9-0 http://www.eiffel.com/developers/xml/configuration-1-9-0.xsd" name="service_file" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486">
<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="service_file" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486">
<target name="service_file">
<root class="SERVICE_FILE" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<setting name="concurrency" value="scoop"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="connector_nino" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf"/>
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf"/>
<library name="http" location="../../library/network/protocol/http/http-safe.ecf"/>
<library name="connector_standalone" location="..\..\library\server\ewsgi\connectors\standalone\standalone-safe.ecf"/>
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf"/>
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
<cluster name="service_file" location=".\" recursive="true">
<file_rule>

View File

@@ -0,0 +1,35 @@
note
description: "Simple file execution, serving home.html, ewf.png and 404.html"
date: "$Date$"
revision: "$Revision$"
class
SERVICE_FILE_EXECUTION
inherit
WSF_EXECUTION
create
make
feature {NONE} -- Initialization
execute
local
mesg: WSF_RESPONSE_MESSAGE
not_found: WSF_NOT_FOUND_RESPONSE
do
if request.path_info.is_case_insensitive_equal_general ("/") then
create {WSF_FILE_RESPONSE} mesg.make_html ("home.html")
elseif request.path_info.is_case_insensitive_equal_general ("/ewf.png") then
create {WSF_FILE_RESPONSE} mesg.make_with_content_type ({HTTP_MIME_TYPES}.image_png ,"ewf.png")
else
create not_found.make (request)
not_found.add_suggested_location (request.absolute_script_url (""), "Home", "Back to home page")
mesg := not_found
end
response.send (mesg)
end
end

View File

@@ -10,16 +10,7 @@ class
inherit
ANY
WSF_ROUTED_SKELETON_SERVICE
undefine
requires_proxy
end
WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE
WSF_NO_PROXY_POLICY
WSF_DEFAULT_SERVICE
WSF_DEFAULT_SERVICE [IMAGE_UPLOADER_EXECUTION]
SHARED_EXECUTION_ENVIRONMENT
@@ -31,224 +22,12 @@ feature {NONE} -- Initialization
make
-- Initialize Current
do
initialize_router
-- To use particular port number (as 9090) with Nino connector
-- Uncomment the following line
set_service_option ("port", 9090)
make_and_launch
end
setup_router
-- Setup router
local
www: WSF_FILE_SYSTEM_HANDLER
do
map_uri_template_agent_with_request_methods ("/upload/{name}{?nb}", agent execute_upload_put, router.methods_put)
map_uri_template_agent ("/upload{?nb}", agent execute_upload)
create www.make_with_path (document_root)
www.set_directory_index (<<"index.html">>)
www.set_not_found_handler (agent execute_not_found)
router.handle_with_request_methods ("", www, router.methods_GET)
end
feature -- Configuration
document_root: PATH
-- Document root to look for files or directories
once
Result := execution_environment.current_working_path.extended ("htdocs")
ensure
not Result.name.ends_with (Operating_environment.directory_separator.out)
end
files_root: PATH
-- Uploaded files will be stored in `files_root' folder
once
Result := document_root.extended ("files")
end
feature -- Execution
execute_not_found (uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
-- `uri' is not found, redirect to default page
do
res.redirect_now_with_content (req.script_url ("/"), uri + ": not found.%NRedirection to " + req.script_url ("/"), "text/html")
end
execute_upload (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Upload page is requested, either GET or POST
-- On GET display the web form to upload file, by passing ?nb=5 you can upload 5 images
-- On POST display the uploaded files
local
l_body: STRING_8
l_safe_filename: STRING_8
fn: PATH
page: WSF_HTML_PAGE_RESPONSE
n: INTEGER
do
if req.is_request_method ("GET") or else not req.has_uploaded_file then
create page.make
page.set_title ("EWF: Upload file")
page.add_style (req.script_url ("style.css"), "all")
create l_body.make_empty
page.set_body (l_body)
l_body.append ("<h1>EWF: Upload image file</h1>%N")
l_body.append ("<form action=%""+ req.script_url ("/upload") +"%" method=%"POST%" enctype=%"multipart/form-data%">%N")
if attached {WSF_STRING} req.query_parameter ("nb") as p_nb and then p_nb.is_integer then
n := p_nb.integer_value
else
n := 1
end
if attached {WSF_STRING} req.query_parameter ("demo") as p_demo then
fn := document_root.extended (p_demo.value)
l_body.append ("File: <input type=%"file%" name=%"uploaded_file[]%" size=%"60%" value=%""+ html_encode (fn.name) +"%"></br>%N")
end
from
until
n = 0
loop
l_body.append ("File: <input type=%"file%" name=%"uploaded_file[]%" size=%"60%" accept=%"image/*%"></br>%N")
n := n - 1
end
l_body.append (" <input type=%"submit%" value=%"Upload%"/>%N</form>")
res.send (page)
else
create l_body.make (255)
l_body.append ("<h1>EWF: Uploaded files</h1>%N")
l_body.append ("<ul>")
n := 0
across
req.uploaded_files as c
loop
n := n + 1
l_body.append ("<li>")
l_body.append ("<div>" + c.item.name + "=" + html_encode (c.item.filename) + " size=" + c.item.size.out + " type=" + c.item.content_type + "</div>")
l_safe_filename := c.item.safe_filename
fn := files_root.extended (l_safe_filename)
if c.item.move_to (fn.name) then
if c.item.content_type.starts_with ("image") then
l_body.append ("%N<a href=%"../files/" + url_encode (l_safe_filename) + "%"><img src=%"../files/"+ l_safe_filename +"%" /></a>")
else
l_body.append ("File " + html_encode (c.item.filename) + " is not a supported image<br/>%N")
end
end
l_body.append ("</li>")
end
l_body.append ("</ul>")
create page.make
page.set_title ("EWF: uploaded image")
page.add_style ("../style.css", "all")
page.set_body (l_body)
res.send (page)
end
end
execute_upload_put (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Upload page is requested, PUT
require
is_put_request_method: req.is_put_request_method
local
l_body: STRING_8
l_safe_filename: detachable READABLE_STRING_32
fn: PATH
page: WSF_HTML_PAGE_RESPONSE
n: INTEGER
do
create l_body.make (255)
l_body.append ("<h1>EWF: Uploaded files</h1>%N")
l_body.append ("<ul>")
n := 0
if attached {WSF_STRING} req.path_parameter ("name") as p_name then
l_safe_filename := p_name.value
end
if l_safe_filename = Void or else l_safe_filename.is_empty then
l_safe_filename := "input_data"
end
if n = 0 and req.content_length_value > 0 then
if attached new_temporary_output_file ("tmp-uploaded-file_" + n.out) as f then
req.read_input_data_into_file (f)
f.close
fn := files_root.extended (l_safe_filename)
f.rename_file (fn.name)
l_body.append ("<li>")
l_body.append ("<div>Input data : size=" + f.count.out + " (" + req.content_length_value.out + ")</div>")
l_body.append ("%N<a href=%"../files/" + url_encode (l_safe_filename) + "%">"+ html_encode (l_safe_filename) +"</a>")
l_body.append ("</li>")
end
end
l_body.append ("</ul>")
create page.make
page.set_title ("EWF: uploaded image")
page.add_style ("../style.css", "all")
page.set_body (l_body)
res.send (page)
end
feature {NONE} -- Encoder
new_temporary_output_file (n: detachable READABLE_STRING_8): detachable FILE
local
bp: detachable PATH
d: DIRECTORY
i: INTEGER
do
create bp.make_current
create d.make_with_path (bp)
if not d.exists then
d.recursive_create_dir
end
if n /= Void then
bp := bp.extended ("tmp-download-" + n)
else
bp := bp.extended ("tmp")
end
from
i := 0
until
Result /= Void or i > 100
loop
i := i + 1
create {RAW_FILE} Result.make_with_path (bp.appended ("__" + i.out))
if Result.exists then
Result := Void
else
Result.open_write
end
end
ensure
Result /= Void implies Result.is_open_write
end
url_encode (s: READABLE_STRING_32): STRING_8
-- URL Encode `s' as Result
do
Result := url_encoder.encoded_string (s)
end
url_encoder: URL_ENCODER
once
create Result
end
html_encode (s: READABLE_STRING_32): STRING_8
-- HTML Encode `s' as Result
do
Result := html_encoder.encoded_string (s)
end
html_encoder: HTML_ENCODER
once
create Result
end
note
copyright: "2011-2012, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -0,0 +1,242 @@
note
description: "Summary description for {IMAGE_UPLOADER_EXECUTION}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
IMAGE_UPLOADER_EXECUTION
inherit
WSF_ROUTED_SKELETON_EXECUTION
undefine
requires_proxy
redefine
initialize
end
WSF_NO_PROXY_POLICY
WSF_ROUTED_URI_TEMPLATE_HELPER
SHARED_EXECUTION_ENVIRONMENT
create
make
feature {NONE} -- Initialization
initialize
do
Precursor
initialize_router
end
setup_router
-- Setup router
local
www: WSF_FILE_SYSTEM_HANDLER
do
map_uri_template_agent_with_request_methods ("/upload/{name}{?nb}", agent execute_upload_put, router.methods_put)
map_uri_template_agent ("/upload{?nb}", agent execute_upload)
create www.make_with_path (document_root)
www.set_directory_index (<<"index.html">>)
www.set_not_found_handler (agent execute_not_found)
router.handle_with_request_methods ("", www, router.methods_GET)
end
feature -- Configuration
document_root: PATH
-- Document root to look for files or directories
once
Result := execution_environment.current_working_path.extended ("htdocs")
end
files_root: PATH
-- Uploaded files will be stored in `files_root' folder
once
Result := document_root.extended ("files")
end
feature -- Execution
execute_not_found (uri: READABLE_STRING_8; req: WSF_REQUEST; res: WSF_RESPONSE)
-- `uri' is not found, redirect to default page
do
res.redirect_now_with_content (req.script_url ("/"), uri + ": not found.%NRedirection to " + req.script_url ("/"), "text/html")
end
execute_upload (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Upload page is requested, either GET or POST
-- On GET display the web form to upload file, by passing ?nb=5 you can upload 5 images
-- On POST display the uploaded files
local
l_body: STRING_8
l_safe_filename: STRING_8
fn: PATH
page: WSF_HTML_PAGE_RESPONSE
n: INTEGER
do
if req.is_request_method ("GET") or else not req.has_uploaded_file then
create page.make
page.set_title ("EWF: Upload file")
page.add_style (req.script_url ("style.css"), "all")
create l_body.make_empty
page.set_body (l_body)
l_body.append ("<h1>EWF: Upload image file</h1>%N")
l_body.append ("<form action=%""+ req.script_url ("/upload") +"%" method=%"POST%" enctype=%"multipart/form-data%">%N")
if attached {WSF_STRING} req.query_parameter ("nb") as p_nb and then p_nb.is_integer then
n := p_nb.integer_value
else
n := 1
end
if attached {WSF_STRING} req.query_parameter ("demo") as p_demo then
fn := document_root.extended (p_demo.value)
l_body.append ("File: <input type=%"file%" name=%"uploaded_file[]%" size=%"60%" value=%""+ html_encode (fn.name) +"%"></br>%N")
end
from
until
n = 0
loop
l_body.append ("File: <input type=%"file%" name=%"uploaded_file[]%" size=%"60%" accept=%"image/*%"></br>%N")
n := n - 1
end
l_body.append (" <input type=%"submit%" value=%"Upload%"/>%N</form>")
res.send (page)
else
create l_body.make (255)
l_body.append ("<h1>EWF: Uploaded files</h1>%N")
l_body.append ("<ul>")
n := 0
across
req.uploaded_files as c
loop
n := n + 1
l_body.append ("<li>")
l_body.append ("<div>" + c.item.name + "=" + html_encode (c.item.filename) + " size=" + c.item.size.out + " type=" + c.item.content_type + "</div>")
l_safe_filename := c.item.safe_filename
fn := files_root.extended (l_safe_filename)
if c.item.move_to (fn.name) then
if c.item.content_type.starts_with ("image") then
l_body.append ("%N<a href=%"../files/" + url_encode (l_safe_filename) + "%"><img src=%"../files/"+ l_safe_filename +"%" /></a>")
else
l_body.append ("File " + html_encode (c.item.filename) + " is not a supported image<br/>%N")
end
end
l_body.append ("</li>")
end
l_body.append ("</ul>")
create page.make
page.set_title ("EWF: uploaded image")
page.add_style ("../style.css", "all")
page.set_body (l_body)
res.send (page)
end
end
execute_upload_put (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Upload page is requested, PUT
require
is_put_request_method: req.is_put_request_method
local
l_body: STRING_8
l_safe_filename: detachable READABLE_STRING_32
fn: PATH
page: WSF_HTML_PAGE_RESPONSE
n: INTEGER
do
create l_body.make (255)
l_body.append ("<h1>EWF: Uploaded files</h1>%N")
l_body.append ("<ul>")
n := 0
if attached {WSF_STRING} req.path_parameter ("name") as p_name then
l_safe_filename := p_name.value
end
if l_safe_filename = Void or else l_safe_filename.is_empty then
l_safe_filename := "input_data"
end
if n = 0 and req.content_length_value > 0 then
if attached new_temporary_output_file ("tmp-uploaded-file_" + n.out) as f then
req.read_input_data_into_file (f)
f.close
fn := files_root.extended (l_safe_filename)
f.rename_file (fn.name)
l_body.append ("<li>")
l_body.append ("<div>Input data : size=" + f.count.out + " (" + req.content_length_value.out + ")</div>")
l_body.append ("%N<a href=%"../files/" + url_encode (l_safe_filename) + "%">"+ html_encode (l_safe_filename) +"</a>")
l_body.append ("</li>")
end
end
l_body.append ("</ul>")
create page.make
page.set_title ("EWF: uploaded image")
page.add_style ("../style.css", "all")
page.set_body (l_body)
res.send (page)
end
feature {NONE} -- Encoder
new_temporary_output_file (n: detachable READABLE_STRING_8): detachable FILE
local
bp: detachable PATH
d: DIRECTORY
i: INTEGER
do
create bp.make_current
create d.make_with_path (bp)
if not d.exists then
d.recursive_create_dir
end
if n /= Void then
bp := bp.extended ("tmp-download-" + n)
else
bp := bp.extended ("tmp")
end
from
i := 0
until
Result /= Void or i > 100
loop
i := i + 1
create {RAW_FILE} Result.make_with_path (bp.appended ("__" + i.out))
if Result.exists then
Result := Void
else
Result.open_write
end
end
ensure
Result /= Void implies Result.is_open_write
end
url_encode (s: READABLE_STRING_32): STRING_8
-- URL Encode `s' as Result
do
Result := url_encoder.encoded_string (s)
end
url_encoder: URL_ENCODER
once
create Result
end
html_encode (s: READABLE_STRING_32): STRING_8
-- HTML Encode `s' as Result
do
Result := html_encoder.encoded_string (s)
end
html_encoder: HTML_ENCODER
once
create Result
end
end

Some files were not shown because too many files have changed in this diff Show More