Compare commits
40 Commits
es_rev9840
...
es_rev9919
| Author | SHA1 | Date | |
|---|---|---|---|
| 40fb3893af | |||
| 21407f8dcf | |||
| 356eb143ea | |||
| df551d4a4f | |||
| f010da04e9 | |||
| 5029049ef0 | |||
| 80254b2278 | |||
| 210fae5000 | |||
| 9cc9b95190 | |||
| 8b172b5d33 | |||
| cc2d7dbb1c | |||
| c88394b9fd | |||
| 4283662f43 | |||
| 1b951376f9 | |||
| 193cc3cbde | |||
| b49e841ac7 | |||
| 8ba74e1c90 | |||
| 0cecb9594c | |||
| e384a6d6ed | |||
| 71a5c086a5 | |||
| dfa60bf8f5 | |||
| 113aa69efc | |||
| af5fc75743 | |||
|
|
e53c960a89 | ||
|
|
63be2c278c | ||
|
|
f8ba741aa2 | ||
|
|
fe07af587d | ||
|
|
a3a9dd1393 | ||
|
|
fbb860024d | ||
|
|
a14488346f | ||
|
|
f74d1b3069 | ||
|
|
1ba3528974 | ||
| 5890ca6f73 | |||
| 7f4bf09d84 | |||
|
|
ad90e7c135 | ||
| cc3c8af6b4 | |||
| b35ec65577 | |||
| 4482520a86 | |||
| e9afc9ad17 | |||
| 55ab6969ee |
@@ -8,7 +8,8 @@ note
|
|||||||
title: Eiffel Nino Web Server
|
title: Eiffel Nino Web Server
|
||||||
description: Simple HTTPd server written in Eiffel
|
description: Simple HTTPd server written in Eiffel
|
||||||
tags: web, httpd, server
|
tags: web, httpd, server
|
||||||
|
copyright: Javier Velilla, Jocelyn Fiat and Eiffel Software.
|
||||||
license: Eiffel Forum v2
|
license: Eiffel Forum v2
|
||||||
copyright: Javier Velilla, Jocelyn Fiat.
|
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
10
doc/readme.md
Normal file
10
doc/readme.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Welcome to the EiffelWeb framework documentation.
|
||||||
|
|
||||||
|
The EiffelWeb framework is also known as *EWF*.
|
||||||
|
|
||||||
|
The [Workbook](/doc/workbook/workbook.md) lets you discover the EiffelWeb framework.
|
||||||
|
|
||||||
|
And you may found in the *old* [Wiki](/doc/wiki/readme.md) notes that were not migrated to the [Workbook](/doc/workbook/workbook.md), but consider them as obsolete.
|
||||||
|
|
||||||
|
[Enter the documentation](/doc/workbook/workbook.md)
|
||||||
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
## Diagram: Overview of the server architecture ##
|
## Diagram: Overview of the server architecture ##
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/doc/workbook/handling_request/form.md)
|
Nav: [Workbook](../workbook.md) :: [Handling Requests: Form/Query Parameter](../handling_request/form.md)
|
||||||
|
|
||||||
|
|
||||||
## EWF basic service
|
## EWF basic service
|
||||||
@@ -11,14 +11,15 @@ Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/doc
|
|||||||
- [Source code](#source_2)
|
- [Source code](#source_2)
|
||||||
|
|
||||||
|
|
||||||
<a name="structure"/>
|
<a name="structure"></a>
|
||||||
|
|
||||||
## EWF service structure
|
## EWF service structure
|
||||||
|
|
||||||
The following code describes the basic structure of an EWF basic service that handles HTTP requests. We will need to define a Service Launcher and a Request Execution implementation.
|
The following code describes the basic structure of an EWF basic service that handles HTTP requests. We will need to define a Service Launcher and a Request Execution implementation.
|
||||||
|
|
||||||
```eiffel
|
```eiffel
|
||||||
class
|
class
|
||||||
APPLICACTION
|
APPLICATION
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||||
@@ -91,11 +92,11 @@ The **WSF_RESPONSE** provides features to define the response with information s
|
|||||||
|
|
||||||
**APPLICATION** is the root class of our example, it launches the application, using the corresponding connector, Which connector? this depends how you want to run it cgi, fcgi,nino or standalone. For development is recommended to use a standalone web server written in Eiffel, and run the execution within the EiffelStudio debugger. For production fcgi (or cgi) using Apache or another popular web server.
|
**APPLICATION** is the root class of our example, it launches the application, using the corresponding connector, Which connector? this depends how you want to run it cgi, fcgi,nino or standalone. For development is recommended to use a standalone web server written in Eiffel, and run the execution within the EiffelStudio debugger. For production fcgi (or cgi) using Apache or another popular web server.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
**WS_LAUNCHABLE_SERVICE** inherit from **WS_SERVICE** class, which is a marker interface in EWF. And also provides a way to launch our application using different kind of connectors. The class **WSF_DEFAULT_SERVICE_I**, inherit from **WS_LAUNCHABLE_SERVICE** and has a formal generic that should conform to **WSF_SERVICE_LAUNCHER [WSF_EXECUTION]**. Below a [BON diagram] (http://www.bon-method.com/index_normal.htm) showing one of the possible options.
|
**WS_LAUNCHABLE_SERVICE** inherit from **WS_SERVICE** class, which is a marker interface in EWF. And also provides a way to launch our application using different kind of connectors. The class **WSF_DEFAULT_SERVICE_I**, inherit from **WS_LAUNCHABLE_SERVICE** and has a formal generic that should conform to **WSF_SERVICE_LAUNCHER [WSF_EXECUTION]**. Below a [BON diagram](http://www.bon-method.com/index_normal.htm) showing one of the possible options.
|
||||||
|
|
||||||

|

|
||||||
Other connectors:
|
Other connectors:
|
||||||
|
|
||||||
**WSF_STANDALONE_SERVICE_LAUNCHER**
|
**WSF_STANDALONE_SERVICE_LAUNCHER**
|
||||||
@@ -109,11 +110,12 @@ The **APPLICATION_EXECUTION** class inherits from **WSF_EXECUTION** interface,
|
|||||||
|
|
||||||
In the **APPLICATION_EXECUTION** class class you will need to implement implement the **execute** feature, get data from the request *req* and write the response in *res*.
|
In the **APPLICATION_EXECUTION** class class you will need to implement implement the **execute** feature, get data from the request *req* and write the response in *res*.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The WSF_EXECUTION instance, in this case ```APPLICATION_EXECUTION``` is created per request, with two main attributes request: ```WSF_REQUEST``` and response: ```WSF_RESPONSE```.
|
The WSF_EXECUTION instance, in this case ```APPLICATION_EXECUTION``` is created per request, with two main attributes request: ```WSF_REQUEST``` and response: ```WSF_RESPONSE```.
|
||||||
|
|
||||||
<a name="text"/>
|
<a name="text"></a>
|
||||||
|
|
||||||
## A simple Service to Generate Plain Text.
|
## A simple Service to Generate Plain Text.
|
||||||
|
|
||||||
Before to continue, it is recommended to review the getting started guided. In the example we will only shows the implementation of the WSF_EXECUTION interface.
|
Before to continue, it is recommended to review the getting started guided. In the example we will only shows the implementation of the WSF_EXECUTION interface.
|
||||||
@@ -142,16 +144,18 @@ end
|
|||||||
|
|
||||||
```
|
```
|
||||||
<a name="source_1"></a>
|
<a name="source_1"></a>
|
||||||
##### Source code
|
|
||||||
|
### Source code
|
||||||
The source code is available on Github. You can get it by running the command:
|
The source code is available on Github. You can get it by running the command:
|
||||||
|
|
||||||
```git clone https://github.com/EiffelWebFramework/ewf.git```
|
```git clone https://github.com/EiffelWebFramework/ewf.git```
|
||||||
|
|
||||||
The example of simple service that generate plain text response is located in the directory $PATH/ewd/doc/workbook/basics/simple, where $PATH is where you run ```git clone``` . Just double click on the simple.ecf file and select the simple_nino target or if you prefer the command line, run the command:
|
The example of simple service that generate plain text response is located in the directory $PATH/ewf/doc/workbook/basics/simple, where $PATH is where you run ```git clone``` . Just double click on the simple.ecf file and select the simple_nino target or if you prefer the command line, run the command:
|
||||||
|
|
||||||
```estudio -config simple.ecf -target simple_nino```
|
```estudio -config simple.ecf -target simple_nino```
|
||||||
|
|
||||||
<a name="html"></a>
|
<a name="html"></a>
|
||||||
|
|
||||||
## A Service to Generate HTML.
|
## A Service to Generate HTML.
|
||||||
To generate HTML, it's needed
|
To generate HTML, it's needed
|
||||||
|
|
||||||
@@ -193,7 +197,10 @@ feature -- Basic operations
|
|||||||
|
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
##### Source code
|
|
||||||
|
<a name="source_2"></a>
|
||||||
|
|
||||||
|
### Source code
|
||||||
The source code is available on Github. You can get it by running the command:
|
The source code is available on Github. You can get it by running the command:
|
||||||
|
|
||||||
```git clone https://github.com/EiffelWebFramework/ewf.git```
|
```git clone https://github.com/EiffelWebFramework/ewf.git```
|
||||||
@@ -202,5 +209,5 @@ The example of the service that generates HTML is located in the directory $PATH
|
|||||||
|
|
||||||
```estudio -config simple_html.ecf -target simple_html_nino```
|
```estudio -config simple_html.ecf -target simple_html_nino```
|
||||||
|
|
||||||
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/doc/workbook/handling_request/form.md)
|
Nav: [Workbook](../workbook.md) :: [Handling Requests: Form/Query Parameter](../handling_request/form.md)
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,32 @@
|
|||||||
##Run simple_html example on Apache with FCGI on Windows.
|
Nav: [Workbook](../../../workbook.md) :: [Basic concepts](../../../basics/basics.md)
|
||||||
|
|
||||||
|
## Run simple_html example on Apache with FCGI on Windows.
|
||||||
|
|
||||||
|
|
||||||
|
#### Prerequisites
|
||||||
####Prerequisites
|
|
||||||
|
|
||||||
* This tutorial was written for people working under Windows environment, and using Apache Server with FCGI connector
|
* This tutorial was written for people working under Windows environment, and using Apache Server with FCGI connector
|
||||||
* Compile the ewf application from command line.
|
* Compile the ewf application from command line.
|
||||||
* Assuming you have installed Apache Server under C:/home/server/Apache24.
|
* 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 placed your current project under `C:/home/server/Apache24/fcgi-bin`.
|
||||||
* Assuming you have setted the Listen to 8888, the defautl value is 80 .
|
* Assuming you have setted the Listen to `8888`, the defautl value is `80` .
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
####FCGI module
|
#### 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
|
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
|
and copy the _mod_fcgid.so_ to `C:/home/server/Apache24/modules`
|
||||||
|
|
||||||
####Compile the project simple_html using the fcgi connector.
|
#### Compile the project simple_html using the fcgi connector.
|
||||||
|
|
||||||
ec -config simple_html.ecf -target simple_html_fcgi -finalize -c_compile -project_path .
|
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.
|
Copy the genereted exe to `C:/home/server/Apache24/fcgi-bin` folder.
|
||||||
|
|
||||||
Check if you have _libfcgi.dll_ in your PATH.
|
Check if you have _libfcgi.dll_ in your PATH.
|
||||||
|
|
||||||
|
|
||||||
####Apache configuration
|
#### Apache configuration
|
||||||
Add to httpd.conf the content, you can get the configuration file [here](config.conf)
|
Add to httpd.conf the content, you can get the configuration file [here](config.conf)
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -43,10 +44,18 @@ LoadModule fcgid_module modules/mod_fcgid.so
|
|||||||
```
|
```
|
||||||
|
|
||||||
Test if your httpd.conf is ok
|
Test if your httpd.conf is ok
|
||||||
>httpd -t
|
```
|
||||||
|
> httpd -t
|
||||||
|
```
|
||||||
|
|
||||||
Luanch the server
|
Launch the server
|
||||||
>httpd
|
```
|
||||||
|
> httpd
|
||||||
|
```
|
||||||
|
|
||||||
Check the application
|
Check the application
|
||||||
>http://localhost:8888/simple
|
```
|
||||||
|
> http://localhost:8888/simple
|
||||||
|
```
|
||||||
|
|
||||||
|
Nav: [Workbook](../../../workbook.md) :: [Basic concepts](../../../basics/basics.md)
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
#include <windows.h>
|
|
||||||
|
|
||||||
STRINGTABLE
|
|
||||||
BEGIN
|
|
||||||
1 "This Program was made using EiffelStudio using Visual Studio C++"
|
|
||||||
END
|
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
|
Nav: [Workbook](../workbook.md)
|
||||||
|
|
||||||
EWF Deployment
|
EWF Deployment
|
||||||
==============
|
==============
|
||||||
|
|
||||||
#Apache on Windows#
|
# Apache on Windows#
|
||||||
|
|
||||||
1. Apache Install
|
1. Apache Install
|
||||||
2. Deploying EWF CGI
|
2. Deploying EWF CGI
|
||||||
@@ -15,17 +17,17 @@ EWF Deployment
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
##Apache on Windows
|
## Apache on Windows
|
||||||
|
|
||||||
###Apache Install
|
### Apache Install
|
||||||
|
|
||||||
>Check the correct version (Win 32 or Win64)
|
>Check the correct version (Win 32 or Win64)
|
||||||
>Apache Version: Apache 2.4.4
|
>Apache Version: Apache 2.4.4
|
||||||
>Windows: http://www.apachelounge.com/download/
|
>Windows: http://www.apachelounge.com/download/
|
||||||
|
|
||||||
####Deploying EWF CGI
|
#### Deploying EWF CGI
|
||||||
|
|
||||||
####CGI overview
|
#### CGI overview
|
||||||
>A new process is started for each HTTP request. So if there are N requests to the same >CGI program, the code of the CGI program is loaded into memory N times.
|
>A new process is started for each HTTP request. So if there are N requests to the same >CGI program, the code of the CGI program is loaded into memory N times.
|
||||||
>When a CGI program finishes handling a request, the program terminates.
|
>When a CGI program finishes handling a request, the program terminates.
|
||||||
|
|
||||||
@@ -59,7 +61,7 @@ Check that you have the following modules enabled
|
|||||||
LoadModule cgi_module modules/mod_cgi.so
|
LoadModule cgi_module modules/mod_cgi.so
|
||||||
LoadModule rewrite_module modules/mod_rewrite.so
|
LoadModule rewrite_module modules/mod_rewrite.so
|
||||||
|
|
||||||
####Tip:
|
#### Tip:
|
||||||
>To check the syntax of your httpd.conf file. From command line run the following
|
>To check the syntax of your httpd.conf file. From command line run the following
|
||||||
|
|
||||||
$>httpd - t
|
$>httpd - t
|
||||||
@@ -68,7 +70,7 @@ Check that you have the following modules enabled
|
|||||||
>.htaccess CGI
|
>.htaccess CGI
|
||||||
http://perishablepress.com/stupid-htaccess-tricks/
|
http://perishablepress.com/stupid-htaccess-tricks/
|
||||||
|
|
||||||
####.htaccess
|
#### .htaccess
|
||||||
|
|
||||||
Options +ExecCGI +Includes +FollowSymLinks -Indexes
|
Options +ExecCGI +Includes +FollowSymLinks -Indexes
|
||||||
AddHandler cgi-script exe
|
AddHandler cgi-script exe
|
||||||
@@ -89,11 +91,11 @@ Check that you have the following modules enabled
|
|||||||
>Replace $service with the name of your executable service, for example app_service.exe
|
>Replace $service with the name of your executable service, for example app_service.exe
|
||||||
|
|
||||||
|
|
||||||
####Deploying EWF FCGI
|
#### Deploying EWF FCGI
|
||||||
>To deploy FCGI you will need to download the mod_fcgi module.
|
>To deploy FCGI you will need to download the mod_fcgi module.
|
||||||
>You can get it from here http://www.apachelounge.com/download/
|
>You can get it from here http://www.apachelounge.com/download/
|
||||||
|
|
||||||
####FCGI overview
|
#### FCGI overview
|
||||||
>FastCGI allows a single, long-running process to handle more than one user request while keeping close to the CGI programming model, retaining the simplicity while eliminating the overhead of creating a new process for each request. Unlike converting an application to a web server plug-in, FastCGI applications remain independent of the web server.
|
>FastCGI allows a single, long-running process to handle more than one user request while keeping close to the CGI programming model, retaining the simplicity while eliminating the overhead of creating a new process for each request. Unlike converting an application to a web server plug-in, FastCGI applications remain independent of the web server.
|
||||||
|
|
||||||
* Build EWF application
|
* Build EWF application
|
||||||
@@ -126,10 +128,13 @@ Copy the app.exe and the folder "www" into a folder served by apache2, for exam
|
|||||||
|
|
||||||
>NOTE: By default Apache does not come with fcgid module, so you will need to download it, and put the module under Apache2/modules
|
>NOTE: By default Apache does not come with fcgid module, so you will need to download it, and put the module under Apache2/modules
|
||||||
|
|
||||||
#.htaccess FCGI
|
# .htaccess FCGI
|
||||||
>http://perishablepress.com/stupid-htaccess-tricks/
|
|
||||||
|
|
||||||
####.htaccess
|
```
|
||||||
|
http://perishablepress.com/stupid-htaccess-tricks/
|
||||||
|
```
|
||||||
|
|
||||||
|
#### .htaccess
|
||||||
|
|
||||||
Options +ExecCGI +Includes +FollowSymLinks -Indexes
|
Options +ExecCGI +Includes +FollowSymLinks -Indexes
|
||||||
|
|
||||||
@@ -158,6 +163,4 @@ Copy the app.exe and the folder "www" into a folder served by apache2, for exam
|
|||||||
Replace $service with the name of your executable $service, for example app_service.exe
|
Replace $service with the name of your executable $service, for example app_service.exe
|
||||||
You will need to create an service.ews file, this file will be located at the same place where you copy your app service executable.
|
You will need to create an service.ews file, this file will be located at the same place where you copy your app service executable.
|
||||||
|
|
||||||
|
Nav: [Workbook](../workbook.md)
|
||||||
|
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
Nav: [Workbook](../workbook.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md) | [Handling Cookies](/doc/workbook/handling_cookies/handling_cookies.md)
|
Nav: [Workbook](../workbook.md) :: [Handling Requests: Header Fields](../handling_request/headers.md) :: [Handling Cookies](../handling_cookies/handling_cookies.md)
|
||||||
|
|
||||||
|
|
||||||
## EWF Generating Response
|
## EWF Generating Response
|
||||||
@@ -14,7 +14,8 @@ Nav: [Workbook](../workbook.md) | [Handling Requests: Header Fields](/doc/workbo
|
|||||||
- [Response Header Fields](#header_fields)
|
- [Response Header Fields](#header_fields)
|
||||||
|
|
||||||
|
|
||||||
<a name="format"/>
|
<a name="format"></a>
|
||||||
|
|
||||||
## Format of the HTTP response
|
## Format of the HTTP response
|
||||||
|
|
||||||
As we saw in the previous documents, a request from a user-agent (browser or other client) consists of an HTTP command (usually GET or POST), zero or more request headers (one or more in HTTP 1.1, since Host is required), a blank line, and only in the case of POST/PUT requests, payload data. A typical request looks like the following.
|
As we saw in the previous documents, a request from a user-agent (browser or other client) consists of an HTTP command (usually GET or POST), zero or more request headers (one or more in HTTP 1.1, since Host is required), a blank line, and only in the case of POST/PUT requests, payload data. A typical request looks like the following.
|
||||||
@@ -49,7 +50,8 @@ looks like this:
|
|||||||
|
|
||||||
The status line consists of the HTTP version (HTTP/1.1 in the preceding example), a status code (an integer 200 in the example), and a very short message corresponding to the status code (OK in the example). In most cases, the headers are optional except for Content-Type, which specifies the MIME type of the document that follows. Although most responses contain a document, some don’t. For example, responses to HEAD requests should never include a document, and various status codes essentially indicate failure or redirection (and thus either don’t include a document or include only a short error-message document).
|
The status line consists of the HTTP version (HTTP/1.1 in the preceding example), a status code (an integer 200 in the example), and a very short message corresponding to the status code (OK in the example). In most cases, the headers are optional except for Content-Type, which specifies the MIME type of the document that follows. Although most responses contain a document, some don’t. For example, responses to HEAD requests should never include a document, and various status codes essentially indicate failure or redirection (and thus either don’t include a document or include only a short error-message document).
|
||||||
|
|
||||||
<a name="status_set"/>
|
<a name="status_set"></a>
|
||||||
|
|
||||||
## How to set the status code
|
## How to set the status code
|
||||||
|
|
||||||
If you need to set an arbitrary status code, you can use the ```WSF_RESPONSE.put_header``` feature or the ```WSF_RESPONSE.set_status_code``` feature. An status code of 200 is a default value. See below examples using the mentioned features.
|
If you need to set an arbitrary status code, you can use the ```WSF_RESPONSE.put_header``` feature or the ```WSF_RESPONSE.set_status_code``` feature. An status code of 200 is a default value. See below examples using the mentioned features.
|
||||||
@@ -94,7 +96,8 @@ Example
|
|||||||
```
|
```
|
||||||
Both features takes an INTEGER (the status code) as an formal argument, you can use 200, 300, 500 etc directly, but instead of using explicit numbers, it's recommended to use the constants defined in the class [HTTP_STATUS_CODE](). The name of each constant is based from the standard [HTTP 1.1](https://httpwg.github.io/).
|
Both features takes an INTEGER (the status code) as an formal argument, you can use 200, 300, 500 etc directly, but instead of using explicit numbers, it's recommended to use the constants defined in the class [HTTP_STATUS_CODE](). The name of each constant is based from the standard [HTTP 1.1](https://httpwg.github.io/).
|
||||||
|
|
||||||
<a name="redirect"/>
|
<a name="redirect"></a>
|
||||||
|
|
||||||
## How to redirect to a particular location.
|
## How to redirect to a particular location.
|
||||||
To redirect the response to a new location, we need to send a 302 status code, to do that we use ```{HTTP_STATUS_CODE}.found```
|
To redirect the response to a new location, we need to send a 302 status code, to do that we use ```{HTTP_STATUS_CODE}.found```
|
||||||
|
|
||||||
@@ -145,7 +148,8 @@ The ```WSF_RESPONSE.redirect_now``` feature use the status code ```{HTTP_STATUS_
|
|||||||
|
|
||||||
Using a similar approach we can build features to answer a bad request (400), internal server error (500), etc. We will build a simple example showing the most common HTTP status codes.
|
Using a similar approach we can build features to answer a bad request (400), internal server error (500), etc. We will build a simple example showing the most common HTTP status codes.
|
||||||
|
|
||||||
<a name="status"/>
|
<a name="status"></a>
|
||||||
|
|
||||||
## [HTTP 1.1 Status Codes](https://httpwg.github.io/specs/rfc7231.html#status.codes)
|
## [HTTP 1.1 Status Codes](https://httpwg.github.io/specs/rfc7231.html#status.codes)
|
||||||
The status-code element is a three-digit integer code giving the result of the attempt to understand and satisfy the request. The first digit of the status-code defines the class of response.
|
The status-code element is a three-digit integer code giving the result of the attempt to understand and satisfy the request. The first digit of the status-code defines the class of response.
|
||||||
|
|
||||||
@@ -159,7 +163,8 @@ General categories:
|
|||||||
Note: use ```res.set_status_code({HTTP_STATUS_CODE}.bad_request)``` rather than ```res.set_status_code(400)```.
|
Note: use ```res.set_status_code({HTTP_STATUS_CODE}.bad_request)``` rather than ```res.set_status_code(400)```.
|
||||||
|
|
||||||
|
|
||||||
<a name="example_1"/>
|
<a name="example_1"></a>
|
||||||
|
|
||||||
### Example Staus Codes
|
### Example Staus Codes
|
||||||
Basic Service that builds a simple web page to show the most common status codes
|
Basic Service that builds a simple web page to show the most common status codes
|
||||||
```eiffel
|
```eiffel
|
||||||
@@ -298,7 +303,8 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="example_2"/>
|
<a name="example_2"></a>
|
||||||
|
|
||||||
### Example Generic Search Engine
|
### Example Generic Search Engine
|
||||||
The following example shows a basic EWF service that builds a generic front end for the most used search engines. This example shows how
|
The following example shows a basic EWF service that builds a generic front end for the most used search engines. This example shows how
|
||||||
redirection works, and we will use a tools to play with the API to show differents responses.
|
redirection works, and we will use a tools to play with the API to show differents responses.
|
||||||
@@ -585,7 +591,8 @@ Connection: close
|
|||||||
</html>
|
</html>
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="header_fields"/>
|
<a name="header_fields"></a>
|
||||||
|
|
||||||
## [Response Header Fields](https://httpwg.github.io/specs/rfc7231.html#response.header.fields)
|
## [Response Header Fields](https://httpwg.github.io/specs/rfc7231.html#response.header.fields)
|
||||||
|
|
||||||
The response header fields allow the server to pass additional information about the response beyond what is placed in the status-line. These header fields give information about the server, about further access to the target resource, or about related resources. We can specify cookies, page modification date (for caching), reload a page after a designated period of time, size of the document.
|
The response header fields allow the server to pass additional information about the response beyond what is placed in the status-line. These header fields give information about the server, about further access to the target resource, or about related resources. We can specify cookies, page modification date (for caching), reload a page after a designated period of time, size of the document.
|
||||||
@@ -996,4 +1003,4 @@ There are four categories for response header fields:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Nav: [Workbook](../workbook.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md) | [Handling Cookies](/doc/workbook/handling_cookies/handling_cookies.md)
|
Nav: [Workbook](../workbook.md) :: [Handling Requests: Header Fields](../handling_request/headers.md) :: [Handling Cookies](../handling_cookies/handling_cookies.md)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Nav: [Workbook](../workbook.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md)
|
Nav: [Workbook](../workbook.md) :: [Generating Responses](../generating_response/generating_response.md)
|
||||||
|
|
||||||
# Handling Cookies
|
# Handling Cookies
|
||||||
|
|
||||||
@@ -9,9 +9,10 @@ Nav: [Workbook](../workbook.md) | [Generating Responses](/doc/workbook/generatin
|
|||||||
- [How to read a cookie](#read_cookie)
|
- [How to read a cookie](#read_cookie)
|
||||||
- [Examples](#examples)
|
- [Examples](#examples)
|
||||||
|
|
||||||
<a name="cookie"/>
|
<a name="cookie"></a>
|
||||||
## [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.
|
## Cookie
|
||||||
|
A [cookie](http://httpwg.github.io/specs/rfc6265.html) 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.
|
Cookies are used a lot in web client-server communication.
|
||||||
|
|
||||||
@@ -30,7 +31,8 @@ Client send cookies to server
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="properties"/>
|
<a name="properties"></a>
|
||||||
|
|
||||||
### Cookie properties
|
### Cookie properties
|
||||||
|
|
||||||
- Comment: describe the purpose of the cookie. Note that server doesn’t receive this information when client sends cookie in request header.
|
- Comment: describe the purpose of the cookie. Note that server doesn’t receive this information when client sends cookie in request header.
|
||||||
@@ -43,7 +45,8 @@ Client send cookies to server
|
|||||||
- HttpOnly: Checks whether this Cookie has been marked as HttpOnly.
|
- HttpOnly: Checks whether this Cookie has been marked as HttpOnly.
|
||||||
- Version:
|
- Version:
|
||||||
|
|
||||||
<a name="set_get"/>
|
<a name="set_get"></a>
|
||||||
|
|
||||||
## Write and Read Cookies.
|
## 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
|
To send a cookie to the client we should use the [HTTP_HEADER] class, and call ```h.put_cookie``` feature or
|
||||||
@@ -67,7 +70,8 @@ WSF_REQUEST.cookie (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
|||||||
feature.
|
feature.
|
||||||
|
|
||||||
|
|
||||||
<a name="set_cookie"/>
|
<a name="set_cookie"></a>
|
||||||
|
|
||||||
### How to set Cookies
|
### How to set Cookies
|
||||||
Here we have the feature definitions to set cookies
|
Here we have the feature definitions to set cookies
|
||||||
|
|
||||||
@@ -111,7 +115,8 @@ Example of use:
|
|||||||
res.put_string (web_page)
|
res.put_string (web_page)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
<a name="read_cookie"/>
|
<a name="read_cookie"></a>
|
||||||
|
|
||||||
### How to read Cookies
|
### How to read Cookies
|
||||||
|
|
||||||
Reading a particular cookie
|
Reading a particular cookie
|
||||||
@@ -130,7 +135,8 @@ Reading all the cookies
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
<a name="examples"/>
|
<a name="examples"></a>
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
The following EWF service shows a basic use of cookies.
|
The following EWF service shows a basic use of cookies.
|
||||||
1. It display a message to first-time visitors.
|
1. It display a message to first-time visitors.
|
||||||
@@ -285,4 +291,4 @@ end
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
Nav: [Workbook](../workbook.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md)
|
Nav: [Workbook](../workbook.md) :: [Generating Responses](../generating_response/generating_response.md)
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
Nav: [Workbook](../workbook.md) | [Basic Concepts] (/doc/workbook/basics/basics.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md)
|
Nav: [Workbook](../workbook.md) :: [Basic Concepts](../basics/basics.md) :: [Handling Requests: Header Fields](./headers.md)
|
||||||
|
|
||||||
|
|
||||||
#Handling Requests: Form/Query Data
|
|
||||||
|
|
||||||
|
# Handling Requests: Form/Query Data
|
||||||
|
|
||||||
##### Table of Contents
|
##### Table of Contents
|
||||||
- [Reading Form Data](#read)
|
- [Reading Form Data](#read)
|
||||||
- [Query Parameters](#query)
|
- [Query Parameters](#query)
|
||||||
- [Form Parameters](#form)
|
- [Form Parameters](#form_parameters)
|
||||||
- [Uniform Read](#uniform)
|
- [Uniform Read](#uniform)
|
||||||
- [Reading Parameters and Values](#reading_pv)
|
- [Reading Parameters and Values](#reading_pv)
|
||||||
- [How to read all parameters names](#all_names)
|
- [How to read all parameters names](#all_names)
|
||||||
@@ -34,11 +32,13 @@ Here we will show you how to read input submitted by a user using a Form (GET an
|
|||||||
* client side validattion, server side validations, set default if it's a valid option.
|
* client side validattion, server side validations, set default if it's a valid option.
|
||||||
* How to populate Eiffel objects from the request data.
|
* How to populate Eiffel objects from the request data.
|
||||||
|
|
||||||
<a name="read"/>
|
<a name="read"></a>
|
||||||
|
|
||||||
## Reading Form Data
|
## Reading Form Data
|
||||||
EWF [WSF_REQUEST]() class, provides features to handling this form parsing automatically.
|
EWF [WSF_REQUEST]() class, provides features to handling this form parsing automatically.
|
||||||
|
|
||||||
<a name="query"/>
|
<a name="query"></a>
|
||||||
|
|
||||||
### Query Parameters
|
### Query Parameters
|
||||||
|
|
||||||
WSF_REQUEST.query_parameters: ITERABLE [WSF_VALUE]
|
WSF_REQUEST.query_parameters: ITERABLE [WSF_VALUE]
|
||||||
@@ -46,7 +46,8 @@ EWF [WSF_REQUEST]() class, provides features to handling this form parsing autom
|
|||||||
|
|
||||||
WSF_REQUEST.query_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
WSF_REQUEST.query_parameter (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||||
-- Query parameter for name `a_name'.
|
-- Query parameter for name `a_name'.
|
||||||
<a name="form"/>
|
<a name="form_parameters"></a>
|
||||||
|
|
||||||
### Form Parameters
|
### Form Parameters
|
||||||
|
|
||||||
WSF_REQUEST.form_parameters: ITERABLE [WSF_VALUE]
|
WSF_REQUEST.form_parameters: ITERABLE [WSF_VALUE]
|
||||||
@@ -57,7 +58,8 @@ EWF [WSF_REQUEST]() class, provides features to handling this form parsing autom
|
|||||||
|
|
||||||
The values supplied to form_parameter and query_parameter are case sensitive.
|
The values supplied to form_parameter and query_parameter are case sensitive.
|
||||||
|
|
||||||
<a name="uniform"/>
|
<a name="uniform"></a>
|
||||||
|
|
||||||
### Read Data
|
### 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.
|
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.
|
||||||
|
|
||||||
@@ -70,7 +72,8 @@ So, you use **WSF_REQUEST.item** feature exactly the same way for GET and POST r
|
|||||||
>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
|
>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">
|
<a name="reading_pv"></a>
|
||||||
|
|
||||||
## Reading Parameters and Values
|
## 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.
|
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.
|
||||||
@@ -111,7 +114,8 @@ Suppose we have the following HTML5 form using Method POST. This HTML5 form has
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
```
|
```
|
||||||
<a name="all_names">
|
<a name="all_names"></a>
|
||||||
|
|
||||||
### How to read all parameter names
|
### How to read all parameter names
|
||||||
To read all the parameters names we simple call WSF_REQUEST.form_parameters.
|
To read all the parameters names we simple call WSF_REQUEST.form_parameters.
|
||||||
|
|
||||||
@@ -119,7 +123,8 @@ To read all the parameters names we simple call WSF_REQUEST.form_parameters.
|
|||||||
req: WSF_REQUEST
|
req: WSF_REQUEST
|
||||||
across req.form_parameters as ic loop show_parameter_name (ic.item.key) end
|
across req.form_parameters as ic loop show_parameter_name (ic.item.key) end
|
||||||
```
|
```
|
||||||
<a name="single_values">
|
<a name="single_values"></a>
|
||||||
|
|
||||||
### How to read 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)
|
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)
|
||||||
```
|
```
|
||||||
@@ -131,7 +136,8 @@ To read a particular parameter, a single value, for example `given-name', we sim
|
|||||||
-- Value missing, check the name against the HTML form
|
-- Value missing, check the name against the HTML form
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
<a name="multiple_values">
|
<a name="multiple_values"></a>
|
||||||
|
|
||||||
### How to read 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)
|
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)
|
||||||
@@ -155,7 +161,8 @@ To read multiple values, for example in the case of `languages', we simple call
|
|||||||
```
|
```
|
||||||
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.
|
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">
|
<a name="table_values"></a>
|
||||||
|
|
||||||
### How to read table values
|
### How to read table values
|
||||||
This is particularly useful when you have a request with the following format
|
This is particularly useful when you have a request with the following format
|
||||||
|
|
||||||
@@ -183,7 +190,8 @@ if attached {WSF_TABLE} req.query_parameter ("tab") as l_tab then
|
|||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
<a name="raw_data">
|
<a name="raw_data"></a>
|
||||||
|
|
||||||
## Reading 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.
|
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.
|
||||||
|
|
||||||
@@ -199,7 +207,8 @@ To read raw data you need to do this
|
|||||||
|
|
||||||
> 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
|
> 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>
|
<a name="upload"></a>
|
||||||
|
|
||||||
## Upload Files
|
## Upload Files
|
||||||
How can we read data when the date come from an uploaded file/s?.
|
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.
|
HTML supports a form element ```<input type="File" ... > ``` to upload a single file and ```<input type="File" ... multiplr> ``` to upload multiple files.
|
||||||
@@ -290,7 +299,8 @@ The source code is available on Github. You can get it by running the command:
|
|||||||
The example is located in the directory $PATH/ewf/doc/workbook/upload_file where $PATH is where you run git clone.
|
The example is located in the directory $PATH/ewf/doc/workbook/upload_file where $PATH is where you run git clone.
|
||||||
|
|
||||||
|
|
||||||
<a name=examples>
|
<a name="examples"></a>
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
The source code is available on Github. You can get it by running the command:
|
The source code is available on Github. You can get it by running the command:
|
||||||
|
|
||||||
@@ -303,5 +313,4 @@ The GET example is located in the directory $PATH/ewf/doc/workbook/form/get, and
|
|||||||
>Note: replace <ecf_name> and<target_name> with the corresponding values.
|
>Note: replace <ecf_name> and<target_name> with the corresponding values.
|
||||||
|
|
||||||
|
|
||||||
Nav: [Workbook](../workbook.md) | [Basic Concepts] (/doc/workbook/basics/basics.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md)
|
Nav: [Workbook](../workbook.md) :: [Basic Concepts](../basics/basics.md) :: [Handling Requests: Header Fields](./headers.md)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/doc/workbook/handling_request/form.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md)
|
Nav: [Workbook](../workbook.md) :: [Handling Requests: Form/Query parameters](./form.md) :: [Generating Responses](../generating_response/generating_response.md)
|
||||||
|
|
||||||
|
|
||||||
#Handling Requests: Headers
|
# Handling Requests: Headers
|
||||||
|
|
||||||
##### Introduction
|
##### 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]().
|
- 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]().
|
||||||
@@ -43,6 +43,7 @@ Among other, this means the header fields are exposed with associated CGI field
|
|||||||
- For instance `X-Server` will be known as `HTTP_X_SERVER`.
|
- For instance `X-Server` will be known as `HTTP_X_SERVER`.
|
||||||
|
|
||||||
<a name="read_header"></a>
|
<a name="read_header"></a>
|
||||||
|
|
||||||
## Reading HTTP Header fields
|
## Reading HTTP Header fields
|
||||||
EWF [WSF_REQUEST]() class provides features to access HTTP headers.
|
EWF [WSF_REQUEST]() class provides features to access HTTP headers.
|
||||||
|
|
||||||
@@ -72,7 +73,8 @@ Due to CGI compliance, the original header names are not available, however the
|
|||||||
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).
|
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>
|
<a name="read_line"></a>
|
||||||
####Retrieve information from the Request Line
|
|
||||||
|
#### Retrieve information from the Request Line
|
||||||
|
|
||||||
For convenience, the following sections refer to a request starting with line:
|
For convenience, the following sections refer to a request starting with line:
|
||||||
```
|
```
|
||||||
@@ -102,59 +104,72 @@ Overview of the features
|
|||||||
|
|
||||||
|
|
||||||
<a name="understand"></a>
|
<a name="understand"></a>
|
||||||
|
|
||||||
#### Understanding HTTP 1.1 Request Headers
|
#### 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.
|
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).
|
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>
|
<a name="accept"></a>
|
||||||
|
|
||||||
* [Accept](https://httpwg.github.io/specs/rfc7231.html#header.accept)
|
* [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.
|
- 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]()
|
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>
|
<a name="accept_charset"></a>
|
||||||
|
|
||||||
* [Accept-Charset](https://httpwg.github.io/specs/rfc7231.html#header.accept-charset)
|
* [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).
|
- 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>
|
<a name="accept_encoding"></a>
|
||||||
|
|
||||||
* [Accept-Encoding](https://httpwg.github.io/specs/rfc7231.html#header.accept-encoding)
|
* [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.
|
- 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>
|
<a name="accept_language"></a>
|
||||||
|
|
||||||
* [Accept-Language](https://httpwg.github.io/specs/rfc7231.html#header.accept-language)
|
* [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).
|
- 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>
|
<a name="connection"></a>
|
||||||
|
|
||||||
* [Connection](https://httpwg.github.io/specs/rfc7230.html#header.connection)
|
* [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.
|
- 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.
|
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>
|
<a name="authorization"></a>
|
||||||
|
|
||||||
* [Authorization](https://httpwg.github.io/specs/rfc7235.html#header.authorization)
|
* [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.
|
- The header is used by user agents to authenticate themselves when accessing password protected resources.
|
||||||
|
|
||||||
<a name="content-length"></a>
|
<a name="content-length"></a>
|
||||||
|
|
||||||
* [Content-Length](https://httpwg.github.io/specs/rfc7230.html#header.content-length)
|
* [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.
|
- 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>
|
<a name="cookie"></a>
|
||||||
|
|
||||||
* [Cookie](https://httpwg.github.io/specs/rfc6265.html)
|
* [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).
|
- 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>
|
<a name="host"></a>
|
||||||
|
|
||||||
* [Host](https://httpwg.github.io/specs/rfc7230.html#header.host)
|
* [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.
|
- 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>
|
<a name="if-modified-since"></a>
|
||||||
|
|
||||||
* [If-Modified-Since](https://httpwg.github.io/specs/rfc7232.html#header.if-modified-since)
|
* [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.
|
- 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>
|
<a name="if-unmodified-since"></a>
|
||||||
|
|
||||||
* [If-Unmodified-Since](https://httpwg.github.io/specs/rfc7232.html#header.if-unmodified-since)
|
* [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.
|
- 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”).
|
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>
|
<a name="referer"></a>
|
||||||
|
|
||||||
* [Referer](https://httpwg.github.io/specs/rfc7231.html#header.referer)
|
* [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.
|
- 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.
|
||||||
|
|
||||||
@@ -162,15 +177,17 @@ For example, if you are at Web page A and click on a link to Web page B, the URL
|
|||||||
included in the Referer header when the browser requests Web page B.
|
included in the Referer header when the browser requests Web page B.
|
||||||
|
|
||||||
<a name="user-agent"></a>
|
<a name="user-agent"></a>
|
||||||
|
|
||||||
* [User-Agent](https://httpwg.github.io/specs/rfc7231.html#header.user-agent)
|
* [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.
|
- The "User-Agent" header field contains information about the user agent of the request, which is often used by servers to help identify the scope of reported interoperability problems, to work around or tailor responses to avoid particular user agent limitations, and for analytics regarding browser or operating system use or device.
|
||||||
|
|
||||||
**Note**: the example shows the **WSF_EXECUTION** implementation, that will be used by the service launcher.
|
**Note**: the example shows the **WSF_EXECUTION** implementation, that will be used by the service launcher.
|
||||||
|
|
||||||
<a name="example"></a>
|
<a name="example"></a>
|
||||||
|
|
||||||
#### Building a Table of All Request Headers
|
#### Building a Table of All Request Headers
|
||||||
|
|
||||||
The following [EWF service](/doc/workbook/handling_request/headers/header_fields/application.e) code simply uses an ```html_template``` to fill a table (names and values) with all the headers fields it receives.
|
The 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 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).
|
||||||
|
|
||||||
@@ -276,6 +293,7 @@ end
|
|||||||
```
|
```
|
||||||
|
|
||||||
<a name="compress"></a>
|
<a name="compress"></a>
|
||||||
|
|
||||||
#### How to compress pages
|
#### How to compress pages
|
||||||
To be completed.
|
To be completed.
|
||||||
|
|
||||||
@@ -284,7 +302,7 @@ To be completed.
|
|||||||
|
|
||||||
#### Detecting Browser Types
|
#### Detecting Browser Types
|
||||||
|
|
||||||
The User-Agent header identifies the specific browser/client that is sending the request. The following code shows a [EWF service](/doc/workbook/handling_request/headers/browser_name/application.e) that sends browser-specific responses.
|
The 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.
|
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```
|
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```
|
||||||
@@ -429,10 +447,8 @@ As an exercise, try to write a similar service to retrieve the OS family using t
|
|||||||
* [SERVER_SOFTWARE](https://tools.ietf.org/html/rfc3875#section-4.1.16)
|
* [SERVER_SOFTWARE](https://tools.ietf.org/html/rfc3875#section-4.1.16)
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
An [EWF service](/doc/workbook/handling_request/headers/cgi_variables/application.e) that shows the CGI variables, creates a table showing the values of all the CGI variables.
|
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] (/doc/workbook/handling_request/form.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md)
|
|
||||||
|
|
||||||
|
|
||||||
|
Nav: [Workbook](../workbook.md) :: [Handling Requests: Form/Query parameters](./form.md) :: [Generating Responses](../generating_response/generating_response.md)
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,4 @@
|
|||||||
Introduction
|
The [Workbook](./workbook.md) lets you discover the EiffelWeb framework.
|
||||||
|
|
||||||
Basic Concepts
|
|
||||||
Generating Plain Text
|
|
||||||
Generation HTML
|
|
||||||
|
|
||||||
Handling Client Request:
|
[Enter the documentation](./workbook.md)
|
||||||
Form Data
|
|
||||||
Request Heders
|
|
||||||
Query Parameters.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,38 +5,46 @@
|
|||||||
* [EWF Introduction](#introduction)
|
* [EWF Introduction](#introduction)
|
||||||
* [Handling Requests: Form/Query Parameter](#form_query_parameters)
|
* [Handling Requests: Form/Query Parameter](#form_query_parameters)
|
||||||
* [Handling Requests: Header Fields](#header_fields)
|
* [Handling Requests: Header Fields](#header_fields)
|
||||||
* [Generating Responses](#generating responses)
|
* [Generating Responses](#generating_responses)
|
||||||
* [Handling Cookies](#handling_cookies)
|
* [Handling Cookies](#handling_cookies)
|
||||||
* [EWF Deployment](#deployment)
|
* [EWF Deployment](#deployment)
|
||||||
|
|
||||||
<a name="core"></a>
|
<a name="core"></a>
|
||||||
|
|
||||||
# EWF Core
|
# EWF Core
|
||||||
Before reading (or walking throught) the workbook, to get a quick overview of EWF, it is recommended to read the following articles:
|
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/)
|
* [Getting Started with EWF](http://eiffelwebframework.github.io/EWF/getting-started/)
|
||||||
* [EWF Documentation](http://eiffelwebframework.github.io/EWF/wiki/Documentation/)
|
* [EWF Documentation](http://eiffelwebframework.github.io/EWF/workbook/workbook)
|
||||||
* [EWF Application Lifecyle](https://github.com/EiffelWebFramework/ewf_examples/wiki/Application-Lifecycle)
|
* [EWF Application Lifecyle](https://github.com/EiffelWebFramework/ewf_examples/wiki/Application-Lifecycle)
|
||||||
|
|
||||||
|
|
||||||
<a name="introduction"></a>
|
<a name="introduction"></a>
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
[Basic Concepts] (/doc/workbook/basics/basics.md).
|
[Basic Concepts](./basics/basics.md).
|
||||||
|
|
||||||
<a name="form_query_parameters"></a>
|
<a name="form_query_parameters"></a>
|
||||||
|
|
||||||
## Handling Requests: Form/Query Parameter
|
## Handling Requests: Form/Query Parameter
|
||||||
[Handling Requests: Form/Query Parameter] (/doc/workbook/handling_request/form.md).
|
[Handling Requests: Form/Query Parameter](./handling_request/form.md).
|
||||||
|
|
||||||
<a name="header_fields"></a>
|
<a name="header_fields"></a>
|
||||||
|
|
||||||
## Handling Requests: Header Fields
|
## Handling Requests: Header Fields
|
||||||
[Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md).
|
[Handling Requests: Header Fields](./handling_request/headers.md).
|
||||||
|
|
||||||
<a name="generating_responses"></a>
|
<a name="generating_responses"></a>
|
||||||
|
|
||||||
## Generating Response
|
## Generating Response
|
||||||
[Generating Responses](/doc/workbook/generating_response/generating_response.md)
|
[Generating Responses](./generating_response/generating_response.md)
|
||||||
|
|
||||||
<a name="handling_cookies"></a>
|
<a name="handling_cookies"></a>
|
||||||
## Handling Cookies
|
|
||||||
[Handling Cookies](/doc/workbook/handling_cookies/handling_cookies.md)
|
|
||||||
|
|
||||||
<a name="deployment"/>
|
## Handling Cookies
|
||||||
|
[Handling Cookies](./handling_cookies/handling_cookies.md)
|
||||||
|
|
||||||
|
<a name="deployment"></a>
|
||||||
|
|
||||||
## EWF Deployment
|
## EWF Deployment
|
||||||
[EWF Deployment](/doc/workbook/deployment.md)
|
[EWF Deployment](./deployment/readme.md)
|
||||||
|
|||||||
29
examples/proxy/application.e
Normal file
29
examples/proxy/application.e
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
note
|
||||||
|
description: "Launcher for reverse proxy web application."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||||
|
redefine
|
||||||
|
initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make_and_launch
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
initialize
|
||||||
|
-- Initialize current service.
|
||||||
|
do
|
||||||
|
-- Specific to `standalone' connector (the EiffelWeb server).
|
||||||
|
-- See `{WSF_STANDALONE_SERVICE_LAUNCHER}.initialize'
|
||||||
|
set_service_option ("port", 9090)
|
||||||
|
import_service_options (create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI}.make_from_file ("server.ini"))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
49
examples/proxy/application_execution.e
Normal file
49
examples/proxy/application_execution.e
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
note
|
||||||
|
description: "Reverse proxy example."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION_EXECUTION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_EXECUTION
|
||||||
|
|
||||||
|
WSF_URI_REWRITER
|
||||||
|
rename
|
||||||
|
uri as proxy_uri
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Basic operations
|
||||||
|
|
||||||
|
execute
|
||||||
|
do
|
||||||
|
-- NOTE: please enter the target server uri here
|
||||||
|
-- replace "http://localhost:8080/foobar"
|
||||||
|
send_proxy_response ("http://localhost:8080/foobar", Current)
|
||||||
|
end
|
||||||
|
|
||||||
|
send_proxy_response (a_remote: READABLE_STRING_8; a_rewriter: detachable WSF_URI_REWRITER)
|
||||||
|
local
|
||||||
|
h: WSF_SIMPLE_REVERSE_PROXY_HANDLER
|
||||||
|
do
|
||||||
|
create h.make (a_remote)
|
||||||
|
h.set_uri_rewriter (a_rewriter)
|
||||||
|
h.set_uri_rewriter (create {WSF_AGENT_URI_REWRITER}.make (agent proxy_uri))
|
||||||
|
h.set_timeout (30) -- 30 seconds
|
||||||
|
h.set_connect_timeout (5_000) -- milliseconds = 5 seconds
|
||||||
|
h.execute (request, response)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Helpers
|
||||||
|
|
||||||
|
proxy_uri (a_request: WSF_REQUEST): STRING
|
||||||
|
-- Request uri rewriten as url.
|
||||||
|
do
|
||||||
|
Result := a_request.request_uri
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
28
examples/proxy/proxy.ecf
Normal file
28
examples/proxy/proxy.ecf
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="proxy" uuid="B55F0D95-3793-4C90-BBAC-BF5F2DECD5E6" library_target="proxy">
|
||||||
|
<target name="common" abstract="true">
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
<exclude>/CVS$</exclude>
|
||||||
|
<exclude>/EIFGENs$</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>
|
||||||
|
<setting name="console_application" value="true"/>
|
||||||
|
<variable name="ssl_supported" value="false"/>
|
||||||
|
<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"/>
|
||||||
|
<library name="wsf_proxy" location="..\..\library\server\wsf_proxy\wsf_proxy-safe.ecf" readonly="false"/>
|
||||||
|
</target>
|
||||||
|
<target name="proxy" 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>
|
||||||
|
<setting name="concurrency" value="scoop"/>
|
||||||
|
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
||||||
|
<cluster name="proxy" location=".\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
8
examples/proxy/server.ini
Normal file
8
examples/proxy/server.ini
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
verbose=true
|
||||||
|
verbose_level=ALERT
|
||||||
|
port=9090
|
||||||
|
#max_concurrent_connections=100
|
||||||
|
#keep_alive_timeout=15
|
||||||
|
#max_tcp_clients=100
|
||||||
|
#socket_timeout=300
|
||||||
|
#max_keep_alive_requests=300
|
||||||
@@ -10,11 +10,6 @@
|
|||||||
</option>
|
</option>
|
||||||
<setting name="concurrency" value="thread"/>
|
<setting name="concurrency" value="thread"/>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
<library name="connector_standalone" location="..\..\library\server\ewsgi\connectors\standalone\standalone-safe.ecf" readonly="false">
|
|
||||||
<option debug="true">
|
|
||||||
<debug name="standalone" enabled="true"/>
|
|
||||||
</option>
|
|
||||||
</library>
|
|
||||||
<library name="conneg" location="..\..\library\network\protocol\content_negotiation\conneg-safe.ecf"/>
|
<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="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf" readonly="false"/>
|
||||||
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false"/>
|
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false"/>
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ feature {NONE} -- Initialization
|
|||||||
initialize
|
initialize
|
||||||
-- Initialize current service.
|
-- Initialize current service.
|
||||||
do
|
do
|
||||||
set_service_option ("port", 9090)
|
-- Specific to `standalone' connector (the EiffelWeb server).
|
||||||
|
-- See `{WSF_STANDALONE_SERVICE_LAUNCHER}.initialize'
|
||||||
|
set_service_option ("port", 9090)
|
||||||
|
import_service_options (create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI}.make_from_file ("simple.ini"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -17,10 +17,13 @@ feature -- Basic operations
|
|||||||
execute
|
execute
|
||||||
local
|
local
|
||||||
s: STRING
|
s: STRING
|
||||||
do
|
dt: HTTP_DATE
|
||||||
-- To send a response we need to setup, the status code and
|
do
|
||||||
-- the response headers.
|
-- To send a response we need to setup, the status code and
|
||||||
s := "Hello World!"
|
-- the response headers.
|
||||||
|
s := "Hello World!"
|
||||||
|
create dt.make_now_utc
|
||||||
|
s.append (" (UTC time is " + dt.rfc850_string + ").")
|
||||||
response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", s.count.out]>>)
|
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.set_status_code ({HTTP_STATUS_CODE}.ok)
|
||||||
response.header.put_content_type_text_html
|
response.header.put_content_type_text_html
|
||||||
|
|||||||
@@ -1,35 +1,28 @@
|
|||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
<?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">
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="simple" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486" library_target="simple">
|
||||||
<target name="common" abstract="true">
|
<target name="common" abstract="true">
|
||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>/EIFGENs$</exclude>
|
|
||||||
<exclude>/CVS$</exclude>
|
|
||||||
<exclude>/.svn$</exclude>
|
<exclude>/.svn$</exclude>
|
||||||
|
<exclude>/CVS$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
<option warning="true" full_class_checking="false" is_attached_by_default="true" is_obsolete_routine_type="true" void_safety="transitional" syntax="transitional">
|
||||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
</option>
|
</option>
|
||||||
|
<setting name="console_application" value="true"/>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf"/>
|
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf"/>
|
||||||
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
|
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||||
</target>
|
</target>
|
||||||
<target name="simple_standalone" extends="common">
|
<target name="simple_standalone" extends="common">
|
||||||
<root class="APPLICATION" feature="make_and_launch"/>
|
<root class="APPLICATION" feature="make_and_launch"/>
|
||||||
<option warning="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
<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"/>
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
</option>
|
</option>
|
||||||
<setting name="concurrency" value="thread"/>
|
<setting name="concurrency" value="scoop"/>
|
||||||
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
||||||
<cluster name="simple" location=".\" recursive="true"/>
|
<cluster name="simple" location=".\" recursive="true"/>
|
||||||
</target>
|
</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="..\..\library\server\wsf\default\nino-safe.ecf"/>
|
|
||||||
<cluster name="simple" location=".\" recursive="true"/>
|
|
||||||
</target>
|
|
||||||
<target name="simple_cgi" extends="common">
|
<target name="simple_cgi" extends="common">
|
||||||
<root class="APPLICATION" feature="make_and_launch"/>
|
<root class="APPLICATION" feature="make_and_launch"/>
|
||||||
<option warning="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
<option warning="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||||
|
|||||||
8
examples/simple/simple.ini
Normal file
8
examples/simple/simple.ini
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
verbose=true
|
||||||
|
verbose_level=ALERT
|
||||||
|
port=9090
|
||||||
|
#max_concurrent_connections=100
|
||||||
|
#keep_alive_timeout=15
|
||||||
|
#max_tcp_clients=100
|
||||||
|
#socket_timeout=300
|
||||||
|
#max_keep_alive_requests=300
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
</option>
|
</option>
|
||||||
<setting name="concurrency" value="thread"/>
|
<setting name="concurrency" value="thread"/>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base-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="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf"/>
|
||||||
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf"/>
|
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf"/>
|
||||||
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
|
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||||
|
|||||||
29
examples/simple_ssl/application.e
Normal file
29
examples/simple_ssl/application.e
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
note
|
||||||
|
description : "simple application root class"
|
||||||
|
date : "$Date$"
|
||||||
|
revision : "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||||
|
redefine
|
||||||
|
initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make_and_launch
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
initialize
|
||||||
|
-- Initialize current service.
|
||||||
|
do
|
||||||
|
-- Specific to `standalone' connector (the EiffelWeb server).
|
||||||
|
-- See `{WSF_STANDALONE_SERVICE_LAUNCHER}.initialize'
|
||||||
|
set_service_option ("port", 9090)
|
||||||
|
import_service_options (create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI}.make_from_file ("simple.ini"))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
41
examples/simple_ssl/application_execution.e
Normal file
41
examples/simple_ssl/application_execution.e
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
note
|
||||||
|
description : "simple application execution"
|
||||||
|
date : "$Date$"
|
||||||
|
revision : "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION_EXECUTION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_EXECUTION
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Basic operations
|
||||||
|
|
||||||
|
execute
|
||||||
|
local
|
||||||
|
s: STRING
|
||||||
|
dt: HTTP_DATE
|
||||||
|
do
|
||||||
|
-- To send a response we need to setup, the status code and
|
||||||
|
-- the response headers.
|
||||||
|
s := "Hello World!"
|
||||||
|
create dt.make_now_utc
|
||||||
|
s.append (" (UTC time is " + dt.rfc850_string + ").")
|
||||||
|
if request.is_https then
|
||||||
|
s.append ("<p>This is a secured connection! (https)</p>%N")
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
15
examples/simple_ssl/simple.crt
Normal file
15
examples/simple_ssl/simple.crt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICWDCCAcGgAwIBAgIJAJnXGtV+PtiYMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
|
||||||
|
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
||||||
|
aWRnaXRzIFB0eSBMdGQwHhcNMTUwNDAzMjIxNTA0WhcNMTYwNDAyMjIxNTA0WjBF
|
||||||
|
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
|
||||||
|
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
|
||||||
|
gQDFMK6ojzg+KlklhTossR13c51izMgGc3B0z9ttfHIcx2kxra3HtHcKIl5wSUvn
|
||||||
|
G8zmSyFAyQTs5LUv65q46FM9qU8tP+vTeFCfNXvjRcIEpouta3J53K0xuUlxz4d4
|
||||||
|
4D6qvdDWAez/0AkI4y5etW5zXtg7IQorJhsI9TmfGuruzwIDAQABo1AwTjAdBgNV
|
||||||
|
HQ4EFgQUbWpk2HoHa0YqpEwr7CGEatBFTMkwHwYDVR0jBBgwFoAUbWpk2HoHa0Yq
|
||||||
|
pEwr7CGEatBFTMkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAi+h4/
|
||||||
|
IgEocWkdRZBKHEcTrRxz5WhEDJMoVo9LhnXvCfn1G/4p6Un6sYv7Xzpi9NuSY8uV
|
||||||
|
cjfJJXhtF3AtyZ70iTAxWaRWjGaZ03PYOjlledJ5rqJEt6CCn8m+JsfznduZvbxQ
|
||||||
|
zQ6jCLXfyD/tvemB+yYEI3NntvRKx5/zt6Q26Q==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
28
examples/simple_ssl/simple.ini
Normal file
28
examples/simple_ssl/simple.ini
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
##########################################################
|
||||||
|
### EiffelWeb settings for related connector ###
|
||||||
|
### Mostly for EiffelWeb standalone connector ###
|
||||||
|
### See {WGI_STANDALONE_CONSTANTS} for default values. ###
|
||||||
|
##########################################################
|
||||||
|
|
||||||
|
### Connection settings
|
||||||
|
port=9090
|
||||||
|
#max_concurrent_connections=100
|
||||||
|
#max_tcp_clients=100
|
||||||
|
|
||||||
|
### Timeout settings
|
||||||
|
#socket_timeout=60
|
||||||
|
#socket_recv_timeout=5
|
||||||
|
|
||||||
|
### Persistent connection settings
|
||||||
|
#keep_alive_timeout=15
|
||||||
|
#max_keep_alive_requests=100
|
||||||
|
|
||||||
|
### SSL settings
|
||||||
|
# enable SSL, with file certificate.
|
||||||
|
ssl_enabled=true
|
||||||
|
ssl_ca_key=simple.key
|
||||||
|
ssl_ca_crt=simple.crt
|
||||||
|
|
||||||
|
### App settings
|
||||||
|
verbose=true
|
||||||
|
verbose_level=ALERT
|
||||||
15
examples/simple_ssl/simple.key
Normal file
15
examples/simple_ssl/simple.key
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIICXAIBAAKBgQDFMK6ojzg+KlklhTossR13c51izMgGc3B0z9ttfHIcx2kxra3H
|
||||||
|
tHcKIl5wSUvnG8zmSyFAyQTs5LUv65q46FM9qU8tP+vTeFCfNXvjRcIEpouta3J5
|
||||||
|
3K0xuUlxz4d44D6qvdDWAez/0AkI4y5etW5zXtg7IQorJhsI9TmfGuruzwIDAQAB
|
||||||
|
AoGAR5efMg+dieRyLU8rieJcImxVbfOPg9gRsjdtIVkXTR+RL7ow59q7hXBo/Td/
|
||||||
|
WU8cm1gXoJ/bK+71YYqWyB+BaLRIWvRWb7Gdw203tu4e136Ca5uuY+71qdbVTVcl
|
||||||
|
NQ7J+T+eAQFP+a+DdT3ZQxu9eze87SMbu6i5YSpIk2kusOECQQDunv/DQ+nc+NgR
|
||||||
|
DF+Td3sNYUVRT9a1CWi6abAG6reXwp8MS4NobWDf+Ps4JODhEEwlIdq5qL7qqYBZ
|
||||||
|
Gc1TJJ53AkEA0404Fn6vAzzegBcS4RLlYTK7nMr0m4pMmDMCI6YzAYdMmKHp1e6f
|
||||||
|
IwxSmQrmwyAgwcT01bc0+A8yipcC2BWQaQJBAJ01QZm635OGmos41KsKF5bsE8gL
|
||||||
|
SpBBH69Yu/ECqGwie7iU84FUNnO4zIHjwghlPVVlZX3Vz9o4S+fn2N9DC+cCQGyZ
|
||||||
|
QyCxGdC0r5fbwHJQS/ZQn+UGfvlVzqoXDVMVn3t6ZES6YZrT61eHnOM5qGqklIxE
|
||||||
|
Old3vDZXPt/MU8Zvk3kCQBOgUx2VxvTrHN37hk9/QIDiM62+RenBm1M3ah8xTosf
|
||||||
|
1mSeEb6d9Kwb3TgPBmA7YXzJuAQfRIvEPMPxT5SSr6Q=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
27
examples/simple_ssl/simple_ssl.ecf
Normal file
27
examples/simple_ssl/simple_ssl.ecf
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="simple_ssl" uuid="C2FE296C-3C18-4609-A5AB-F604BDEE4410" library_target="simple_ssl">
|
||||||
|
<target name="simple_ssl">
|
||||||
|
<description>Simple EiffelWeb standalone server with SSL support (Concurrent connection supported thanks to SCOOP).</description>
|
||||||
|
<root class="APPLICATION" feature="make_and_launch"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
<exclude>/CVS$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||||
|
<assertions/>
|
||||||
|
</option>
|
||||||
|
<setting name="console_application" value="true"/>
|
||||||
|
<setting name="concurrency" value="scoop"/>
|
||||||
|
<variable name="httpd_ssl_enabled" value="true"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-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="simple" location=".\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="simple_ssl_st" extends="simple_ssl">
|
||||||
|
<description>Simple EiffelWeb standalone server with SSL support (Single threaded, thus no concurrent connection.)</description>
|
||||||
|
<setting name="concurrency" value="none"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
<?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="upload_image" uuid="F2400BE8-D8EB-48EB-B4E4-5D4377062A7F" library_target="upload_image">
|
<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="upload_image" uuid="F2400BE8-D8EB-48EB-B4E4-5D4377062A7F" library_target="upload_image">
|
||||||
<target name="upload_image">
|
<target name="upload_image_common">
|
||||||
<root class="IMAGE_UPLOADER" feature="make"/>
|
|
||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>/EIFGENs$</exclude>
|
<exclude>/EIFGENs$</exclude>
|
||||||
<exclude>/\.git$</exclude>
|
<exclude>/\.git$</exclude>
|
||||||
@@ -11,19 +10,26 @@
|
|||||||
<debug name="standalone" enabled="true"/>
|
<debug name="standalone" enabled="true"/>
|
||||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" supplier_precondition="true"/>
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" supplier_precondition="true"/>
|
||||||
</option>
|
</option>
|
||||||
<setting name="concurrency" value="thread"/>
|
<setting name="concurrency" value="scoop"/>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
<library name="connector_standalone" location="..\..\library\server\ewsgi\connectors\standalone\standalone-safe.ecf" readonly="false" use_application_options="true">
|
|
||||||
<option>
|
|
||||||
<assertions precondition="true" check="true" invariant="true" supplier_precondition="true"/>
|
|
||||||
</option>
|
|
||||||
</library>
|
|
||||||
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false" use_application_options="true"/>
|
|
||||||
<library name="encoder" location="..\..\library\text\encoder\encoder-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="http" location="..\..\library\network\protocol\http\http-safe.ecf" readonly="false"/>
|
||||||
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
||||||
<library name="uri_template" location="..\..\library\text\parser\uri_template\uri_template-safe.ecf" readonly="false"/>
|
<library name="uri_template" location="..\..\library\text\parser\uri_template\uri_template-safe.ecf" readonly="false"/>
|
||||||
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf" readonly="false" use_application_options="true"/>
|
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf" readonly="false" use_application_options="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="upload_image_standalone" extends="upload_image_common">
|
||||||
|
<root class="IMAGE_UPLOADER" feature="make"/>
|
||||||
|
<setting name="concurrency" value="thread"/>
|
||||||
|
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false" use_application_options="true"/>
|
||||||
<cluster name="src" location="src\" recursive="true"/>
|
<cluster name="src" location="src\" recursive="true"/>
|
||||||
</target>
|
</target>
|
||||||
|
<target name="upload_image_libfcgi" extends="upload_image_common">
|
||||||
|
<root class="IMAGE_UPLOADER" feature="make"/>
|
||||||
|
<setting name="concurrency" value="none"/>
|
||||||
|
<library name="default_libfcgi" location="..\..\library\server\wsf\default\libfcgi-safe.ecf" readonly="false" use_application_options="true"/>
|
||||||
|
<cluster name="src" location="src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="upload_image" extends="upload_image_standalone">
|
||||||
|
</target>
|
||||||
</system>
|
</system>
|
||||||
|
|||||||
29
examples/websocket/application.e
Normal file
29
examples/websocket/application.e
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
note
|
||||||
|
description : "simple application root class"
|
||||||
|
date : "$Date$"
|
||||||
|
revision : "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION
|
||||||
|
|
||||||
|
create
|
||||||
|
make_and_launch
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make_and_launch
|
||||||
|
local
|
||||||
|
l_launcher: WSF_STANDALONE_WEBSOCKET_SERVICE_LAUNCHER [APPLICATION_EXECUTION]
|
||||||
|
opts: WSF_SERVICE_LAUNCHER_OPTIONS
|
||||||
|
do
|
||||||
|
create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI} opts.make_from_file ("ws.ini")
|
||||||
|
create l_launcher.make_and_launch (options)
|
||||||
|
end
|
||||||
|
|
||||||
|
options: WSF_SERVICE_LAUNCHER_OPTIONS
|
||||||
|
-- Initialize current service.
|
||||||
|
do
|
||||||
|
create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI} Result.make_from_file ("ws.ini")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
184
examples/websocket/application_execution.e
Normal file
184
examples/websocket/application_execution.e
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
note
|
||||||
|
description : "simple application execution"
|
||||||
|
date : "$Date$"
|
||||||
|
revision : "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION_EXECUTION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_WEBSOCKET_EXECUTION
|
||||||
|
|
||||||
|
WEB_SOCKET_EVENT_I
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Basic operations
|
||||||
|
|
||||||
|
execute
|
||||||
|
local
|
||||||
|
s: STRING
|
||||||
|
dt: HTTP_DATE
|
||||||
|
do
|
||||||
|
-- To send a response we need to setup, the status code and
|
||||||
|
-- the response headers.
|
||||||
|
if request.path_info.same_string_general ("/app") then
|
||||||
|
s := websocket_app_html (9090)
|
||||||
|
else
|
||||||
|
s := "Hello World!"
|
||||||
|
create dt.make_now_utc
|
||||||
|
s.append (" (UTC time is " + dt.rfc850_string + ").")
|
||||||
|
s.append ("<p><a href=%"/app%">Websocket demo</a></p>")
|
||||||
|
end
|
||||||
|
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
|
||||||
|
|
||||||
|
feature -- Websocket execution
|
||||||
|
|
||||||
|
new_websocket_handler (ws: WEB_SOCKET): WEB_SOCKET_HANDLER
|
||||||
|
do
|
||||||
|
create Result.make (ws, Current)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Websocket execution
|
||||||
|
|
||||||
|
on_open (ws: WEB_SOCKET)
|
||||||
|
do
|
||||||
|
ws.put_error ("Connecting")
|
||||||
|
ws.send (Text_frame, "Hello, this is a simple demo with Websocket using Eiffel. (/help for more information).%N")
|
||||||
|
end
|
||||||
|
|
||||||
|
on_binary (ws: WEB_SOCKET; a_message: READABLE_STRING_8)
|
||||||
|
do
|
||||||
|
ws.send (Binary_frame, a_message)
|
||||||
|
end
|
||||||
|
|
||||||
|
on_text (ws: WEB_SOCKET; a_message: READABLE_STRING_8)
|
||||||
|
do
|
||||||
|
if a_message.same_string_general ("/help") then
|
||||||
|
-- Echo the message for testing.
|
||||||
|
ws.send (Text_frame, "Help: available commands%N - /time : return the server UTC time.%N")
|
||||||
|
elseif a_message.starts_with_general ("/time") then
|
||||||
|
ws.send (Text_frame, "Server time is " + (create {HTTP_DATE}.make_now_utc).string)
|
||||||
|
else
|
||||||
|
-- Echo the message for testing.
|
||||||
|
ws.send (Text_frame, a_message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
on_close (ws: WEB_SOCKET)
|
||||||
|
-- Called after the WebSocket connection is closed.
|
||||||
|
do
|
||||||
|
ws.put_error ("Connection closed")
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- HTML Resource
|
||||||
|
|
||||||
|
websocket_app_html (a_port: INTEGER): STRING
|
||||||
|
do
|
||||||
|
Result := "[
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
var socket;
|
||||||
|
|
||||||
|
function connect(){
|
||||||
|
|
||||||
|
var host = "ws://127.0.0.1:##PORTNUMBER##";
|
||||||
|
|
||||||
|
try{
|
||||||
|
socket = new WebSocket(host);
|
||||||
|
message('<p class="event">Socket Status: '+socket.readyState);
|
||||||
|
socket.onopen = function(){
|
||||||
|
message('<p class="event">Socket Status: '+socket.readyState+' (open)');
|
||||||
|
}
|
||||||
|
socket.onmessage = function(msg){
|
||||||
|
message('<p class="message">Received: '+msg.data);
|
||||||
|
}
|
||||||
|
socket.onclose = function(){
|
||||||
|
message('<p class="event">Socket Status: '+socket.readyState+' (Closed)');
|
||||||
|
}
|
||||||
|
} catch(exception){
|
||||||
|
message('<p>Error'+exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function send(){
|
||||||
|
var text = $('#text').val();
|
||||||
|
if(text==""){
|
||||||
|
message('<p class="warning">Please enter a message');
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
socket.send(text);
|
||||||
|
message('<p class="event">Sent: '+text)
|
||||||
|
} catch(exception){
|
||||||
|
message('<p class="warning">');
|
||||||
|
}
|
||||||
|
$('#text').val("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function message(msg){
|
||||||
|
$('#chatLog').append(msg+'</p>');
|
||||||
|
}//End message()
|
||||||
|
|
||||||
|
$('#text').keypress(function(event) {
|
||||||
|
if (event.keyCode == '13') {
|
||||||
|
send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#disconnect').click(function(){
|
||||||
|
socket.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!("WebSocket" in window)){
|
||||||
|
$('#chatLog, input, button, #examples').fadeOut("fast");
|
||||||
|
$('<p>Oh no, you need a browser that supports WebSockets. How about <a href="http://www.google.com/chrome">Google Chrome</a>?</p>').appendTo('#container');
|
||||||
|
}else{
|
||||||
|
//The user has WebSockets
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<style type="text/css">
|
||||||
|
body {font-family:Arial, Helvetica, sans-serif;}
|
||||||
|
#container { border:5px solid grey; width:800px; margin:0 auto; padding:10px; }
|
||||||
|
#chatLog { padding:5px; border:1px solid black; }
|
||||||
|
#chatLog p {margin:0;}
|
||||||
|
.event {color:#999;}
|
||||||
|
.warning { font-weight:bold; color:#CCC; }
|
||||||
|
</style>
|
||||||
|
<title>WebSockets Client</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wrapper">
|
||||||
|
<div id="container">
|
||||||
|
<h1>WebSockets Client</h1>
|
||||||
|
<div id="chatLog"></div>
|
||||||
|
<input id="text" type="text" />
|
||||||
|
<button id="disconnect">Disconnect</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
]"
|
||||||
|
Result.replace_substring_all ("##PORTNUMBER##", a_port.out)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
21
examples/websocket/websocket_app.ecf
Normal file
21
examples/websocket/websocket_app.ecf
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="websocket_app" uuid="75D17C20-10A8-4E4C-A059-33D72A2B6AEF">
|
||||||
|
<target name="websocket_app">
|
||||||
|
<root class="APPLICATION" feature="make_and_launch"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
<exclude>/CVS$</exclude>
|
||||||
|
<exclude>/EIFGENs$</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>
|
||||||
|
<setting name="console_application" value="true"/>
|
||||||
|
<setting name="concurrency" value="scoop"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf"/>
|
||||||
|
<library name="standalone_websocket_connector" location="..\..\library\server\wsf\connector\standalone_websocket-safe.ecf" readonly="false"/>
|
||||||
|
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||||
|
<cluster name="app" location=".\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
8
examples/websocket/ws.ini
Normal file
8
examples/websocket/ws.ini
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
verbose=true
|
||||||
|
verbose_level=INFORMATION
|
||||||
|
port=9090
|
||||||
|
max_concurrent_connections=100
|
||||||
|
keep_alive_timeout=35
|
||||||
|
max_tcp_clients=100
|
||||||
|
socket_timeout=30000
|
||||||
|
max_keep_alive_requests=3000
|
||||||
@@ -3,13 +3,25 @@ package http_client
|
|||||||
project
|
project
|
||||||
http_client = "http_client-safe.ecf"
|
http_client = "http_client-safe.ecf"
|
||||||
http_client = "http_client.ecf"
|
http_client = "http_client.ecf"
|
||||||
|
libcurl_http_client = "libcurl_http_client-safe.ecf"
|
||||||
|
libcurl_http_client = "libcurl_http_client.ecf"
|
||||||
|
net_http_client = "net_http_client-safe.ecf"
|
||||||
|
net_http_client = "net_http_client.ecf"
|
||||||
|
|
||||||
note
|
note
|
||||||
-- title:
|
title: HTTP client
|
||||||
-- description:
|
description: "[
|
||||||
-- tags:
|
Provides simple routines to perform http requests, and get associated response.
|
||||||
-- license:
|
It has two implementations:
|
||||||
-- copyright:
|
- using Eiffel cURL (i.e libcurl)
|
||||||
-- link[doc]: "Documentation" http://
|
- using EiffelNET (and the EiffelNET SSL extension)
|
||||||
|
]"
|
||||||
|
collection:EWF
|
||||||
|
tags: http,client,network,request,web,curl,EWF
|
||||||
|
copyright: 1984-2016 Eiffel Software and others
|
||||||
|
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||||
|
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||||
|
link[source]: "github" https://github.com/EiffelWebFramework/EWF/tree/master/library/network/http_client
|
||||||
|
link[doc]: "Documentation" https://github.com/EiffelWebFramework/EWF/tree/master/library/network/http_client/README.md
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,11 +5,16 @@ project
|
|||||||
conneg = "conneg.ecf"
|
conneg = "conneg.ecf"
|
||||||
|
|
||||||
note
|
note
|
||||||
-- title:
|
title: CONneg Content Negotiation
|
||||||
-- description:
|
description: "[
|
||||||
-- tags:
|
CONneg is a library that provides utilities to select the best repesentation of a resource for a client where there are multiple representations available.
|
||||||
-- license:
|
]"
|
||||||
-- copyright:
|
collection: EWF
|
||||||
-- link[doc]: "Documentation" http://
|
tags: content,accept,conneg,negotiation,EWF,web,request
|
||||||
|
copyright: 2011-2016, Javier Velilla, Jocelyn Fiat, Eiffel Software and others
|
||||||
|
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||||
|
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||||
|
link[source]: "github" https://github.com/EiffelWebFramework/EWF/tree/master/library/network/protocol/content_negotiation
|
||||||
|
link[doc]: "Documentation" https://github.com/EiffelWebFramework/EWF/tree/master/library/network/protocol/content_negotiation/README.md
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,11 +5,22 @@ project
|
|||||||
http = "http.ecf"
|
http = "http.ecf"
|
||||||
|
|
||||||
note
|
note
|
||||||
-- title:
|
title: HTTP protocol
|
||||||
-- description:
|
description: "[
|
||||||
-- tags:
|
Collection of interfaces related to HTTP protocol:
|
||||||
-- license:
|
- header
|
||||||
-- copyright:
|
- status codes, request methods
|
||||||
-- link[doc]: "Documentation" http://
|
- content type, media type, mime type.
|
||||||
|
- cookie
|
||||||
|
- date used in web protocol
|
||||||
|
- file extension mime mapping
|
||||||
|
]"
|
||||||
|
collection: EWF
|
||||||
|
tags: http,web,header,status,method,type,mime,cookie
|
||||||
|
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||||
|
copyright: 2011-2016, Jocelyn Fiat, Eiffel Software and others
|
||||||
|
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||||
|
link[source]: "github" https://github.com/EiffelWebFramework/EWF/tree/master/library/network/protocol/http
|
||||||
|
link[doc]: "Documentation" https://github.com/EiffelWebFramework/EWF/tree/master/library/network/protocol/http/README.md
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ feature {NONE} -- Initialization
|
|||||||
do
|
do
|
||||||
set_name (a_name)
|
set_name (a_name)
|
||||||
set_value(a_value)
|
set_value(a_value)
|
||||||
set_max_age (-1)
|
unset_max_age
|
||||||
ensure
|
ensure
|
||||||
name_set: name = a_name
|
name_set: name = a_name
|
||||||
value_set: value = a_value
|
value_set: value = a_value
|
||||||
@@ -101,15 +101,6 @@ feature -- Access
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
include_max_age: BOOLEAN
|
|
||||||
-- Does the Set-Cookie header include Max-Age attribute?
|
|
||||||
--|By default will include both.
|
|
||||||
|
|
||||||
include_expires: BOOLEAN
|
|
||||||
-- Does the Set-Cookie header include Expires attribute?
|
|
||||||
--|By default will include both.
|
|
||||||
|
|
||||||
|
|
||||||
is_valid_rfc1123_date (a_string: READABLE_STRING_8): BOOLEAN
|
is_valid_rfc1123_date (a_string: READABLE_STRING_8): BOOLEAN
|
||||||
-- Is the date represented by `a_string' a valid rfc1123 date?
|
-- Is the date represented by `a_string' a valid rfc1123 date?
|
||||||
local
|
local
|
||||||
@@ -119,10 +110,56 @@ feature -- Access
|
|||||||
Result := not d.has_error and then d.rfc1123_string.same_string (a_string)
|
Result := not d.has_error and then d.rfc1123_string.same_string (a_string)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature -- Obsolete query
|
||||||
|
|
||||||
|
include_max_age: BOOLEAN
|
||||||
|
obsolete
|
||||||
|
"Use `max_age > 0' [April-2016]"
|
||||||
|
do
|
||||||
|
Result := max_age > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
include_expires: BOOLEAN
|
||||||
|
obsolete
|
||||||
|
"Use `expires /= Void' [April-2016]"
|
||||||
|
do
|
||||||
|
Result := expiration /= Void
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Obsolete element change
|
||||||
|
|
||||||
|
mark_max_age
|
||||||
|
-- Set `max_age > 0'
|
||||||
|
-- Set `expires to void'
|
||||||
|
-- Set-Cookie will include only Max-Age attribute and not Expires.
|
||||||
|
obsolete
|
||||||
|
"Uset `set_max_age' and `unset_*' features to add or remove the attributes from the response header [April-2016]"
|
||||||
|
do
|
||||||
|
max_age := 1
|
||||||
|
expiration := Void
|
||||||
|
ensure
|
||||||
|
max_age_true: include_max_age
|
||||||
|
expire_false: not include_expires
|
||||||
|
end
|
||||||
|
|
||||||
|
mark_expires
|
||||||
|
-- Set `mark_age' to -1.
|
||||||
|
-- Set `expiration to a default date'
|
||||||
|
-- Set-Cookie will include only Expires attribute and not Max_Age.
|
||||||
|
obsolete
|
||||||
|
"Use `set_expiration' and `unset_*' features to add or remove the attribute from the response header [April-2016]"
|
||||||
|
do
|
||||||
|
max_age := -1
|
||||||
|
set_expiration_date (create {DATE_TIME}.make_now_utc)
|
||||||
|
ensure
|
||||||
|
expires_true: include_expires
|
||||||
|
max_age_false: not include_max_age
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Change Element
|
feature -- Change Element
|
||||||
|
|
||||||
set_name (a_name: READABLE_STRING_8)
|
set_name (a_name: READABLE_STRING_8)
|
||||||
-- Set `name' with `a_name'.
|
-- Set `name' to `a_name'.
|
||||||
require
|
require
|
||||||
a_name_not_blank: a_name /= Void and then not a_name.is_whitespace
|
a_name_not_blank: a_name /= Void and then not a_name.is_whitespace
|
||||||
a_name_has_valid_characters: a_name /= Void and then has_valid_characters (a_name)
|
a_name_has_valid_characters: a_name /= Void and then has_valid_characters (a_name)
|
||||||
@@ -133,7 +170,7 @@ feature -- Change Element
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_value (a_value: READABLE_STRING_8)
|
set_value (a_value: READABLE_STRING_8)
|
||||||
-- Set `value' with `a_value'.
|
-- Set `value' to `a_value'.
|
||||||
require
|
require
|
||||||
a_value_has_valid_characters: a_value /= Void and then has_valid_characters (a_value)
|
a_value_has_valid_characters: a_value /= Void and then has_valid_characters (a_value)
|
||||||
do
|
do
|
||||||
@@ -143,7 +180,7 @@ feature -- Change Element
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_expiration (a_date: READABLE_STRING_8)
|
set_expiration (a_date: READABLE_STRING_8)
|
||||||
-- Set `expiration' with `a_date'
|
-- Set `expiration' to RFC1123 date string `a_date'.
|
||||||
require
|
require
|
||||||
rfc1133_date: a_date /= Void and then is_valid_rfc1123_date (a_date)
|
rfc1133_date: a_date /= Void and then is_valid_rfc1123_date (a_date)
|
||||||
do
|
do
|
||||||
@@ -153,7 +190,7 @@ feature -- Change Element
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_expiration_date (a_date: DATE_TIME)
|
set_expiration_date (a_date: DATE_TIME)
|
||||||
-- Set `expiration' with `a_date'
|
-- Set `expiration' to `a_date'.
|
||||||
do
|
do
|
||||||
set_expiration (date_to_rfc1123_http_date_format (a_date))
|
set_expiration (date_to_rfc1123_http_date_format (a_date))
|
||||||
ensure
|
ensure
|
||||||
@@ -161,7 +198,7 @@ feature -- Change Element
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_path (a_path: READABLE_STRING_8)
|
set_path (a_path: READABLE_STRING_8)
|
||||||
-- Set `path' with `a_path'
|
-- Set `path' to `a_path'.
|
||||||
do
|
do
|
||||||
path := a_path
|
path := a_path
|
||||||
ensure
|
ensure
|
||||||
@@ -169,7 +206,7 @@ feature -- Change Element
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_domain (a_domain: READABLE_STRING_8)
|
set_domain (a_domain: READABLE_STRING_8)
|
||||||
-- Set `domain' with `a_domain'
|
-- Set `domain' to `a_domain'.
|
||||||
-- Note: you should avoid using "localhost" as `domain' for local cookies
|
-- Note: you should avoid using "localhost" as `domain' for local cookies
|
||||||
-- since they are not always handled by browser (for instance Chrome)
|
-- since they are not always handled by browser (for instance Chrome)
|
||||||
require
|
require
|
||||||
@@ -181,7 +218,7 @@ feature -- Change Element
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_secure (a_secure: BOOLEAN)
|
set_secure (a_secure: BOOLEAN)
|
||||||
-- Set `secure' with `a_secure'
|
-- Set `secure' to `a_secure'.
|
||||||
do
|
do
|
||||||
secure := a_secure
|
secure := a_secure
|
||||||
ensure
|
ensure
|
||||||
@@ -189,7 +226,7 @@ feature -- Change Element
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_http_only (a_http_only: BOOLEAN)
|
set_http_only (a_http_only: BOOLEAN)
|
||||||
-- Set `http_only' with `a_http_only'
|
-- Set `http_only' to `a_http_only'.
|
||||||
do
|
do
|
||||||
http_only := a_http_only
|
http_only := a_http_only
|
||||||
ensure
|
ensure
|
||||||
@@ -197,48 +234,29 @@ feature -- Change Element
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_max_age (a_max_age: INTEGER)
|
set_max_age (a_max_age: INTEGER)
|
||||||
-- Set `max_age' with `a_max_age'
|
-- Set `max_age' to `a_max_age'.
|
||||||
|
require
|
||||||
|
valid_max_age: a_max_age >= 0
|
||||||
do
|
do
|
||||||
max_age := a_max_age
|
max_age := a_max_age
|
||||||
ensure
|
ensure
|
||||||
max_age_set: max_age = a_max_age
|
max_age_set: max_age = a_max_age
|
||||||
end
|
end
|
||||||
|
|
||||||
|
unset_max_age
|
||||||
mark_max_age
|
-- Set `max_age' to -1.
|
||||||
-- Set `include_max_age' to True.
|
|
||||||
-- Set `include_expires' to False.
|
|
||||||
-- Set-Cookie will include only Max-Age attribute and not Expires.
|
|
||||||
do
|
do
|
||||||
include_max_age := True
|
max_age := -1
|
||||||
include_expires := False
|
|
||||||
ensure
|
ensure
|
||||||
max_age_true: include_max_age
|
max_age_unset: max_age = -1
|
||||||
expire_false: not include_expires
|
|
||||||
end
|
end
|
||||||
|
|
||||||
mark_expires
|
unset_expiration
|
||||||
-- Set `include_expires' to True.
|
-- Set `expiration' to Void.
|
||||||
-- Set `include_max_age' to False
|
|
||||||
-- Set-Cookie will include only Expires attribute and not Max_Age.
|
|
||||||
do
|
do
|
||||||
include_expires := True
|
expiration := Void
|
||||||
include_max_age := False
|
|
||||||
ensure
|
ensure
|
||||||
expires_true: include_expires
|
expiration_void: expiration = Void
|
||||||
max_age_false: not include_max_age
|
|
||||||
end
|
|
||||||
|
|
||||||
set_default_expires_max_age
|
|
||||||
-- Set `include_expires' to False.
|
|
||||||
-- Set `include_max_age' to False
|
|
||||||
-- Set-Cookie will include both Max-Age, Expires attributes.
|
|
||||||
do
|
|
||||||
include_expires := False
|
|
||||||
include_max_age := False
|
|
||||||
ensure
|
|
||||||
expires_false: not include_expires
|
|
||||||
max_age_false: not include_max_age
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Date Utils
|
feature {NONE} -- Date Utils
|
||||||
@@ -270,28 +288,14 @@ feature -- Output
|
|||||||
s.append ("; Path=")
|
s.append ("; Path=")
|
||||||
s.append (l_path)
|
s.append (l_path)
|
||||||
end
|
end
|
||||||
-- Expire
|
|
||||||
if include_expires then
|
|
||||||
if attached expiration as l_expires then
|
|
||||||
s.append ("; Expires=")
|
|
||||||
s.append (l_expires)
|
|
||||||
end
|
|
||||||
-- Max-Age
|
|
||||||
elseif include_max_age then
|
|
||||||
s.append ("; Max-Age=")
|
|
||||||
s.append_integer (max_age)
|
|
||||||
else
|
|
||||||
-- Default
|
|
||||||
check
|
|
||||||
-- By default the attributes include_expires and include_max_age are False.
|
|
||||||
-- Meaning that Expires and Max-Age headers are included in the response.
|
|
||||||
default: (not include_expires) and (not include_max_age)
|
|
||||||
end
|
|
||||||
if attached expiration as l_expires then
|
|
||||||
s.append ("; Expires=")
|
|
||||||
s.append (l_expires)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
-- Expires
|
||||||
|
if attached expiration as l_expires then
|
||||||
|
s.append ("; Expires=")
|
||||||
|
s.append (l_expires)
|
||||||
|
end
|
||||||
|
-- Max-age
|
||||||
|
if max_age >= 0 then
|
||||||
s.append ("; Max-Age=")
|
s.append ("; Max-Age=")
|
||||||
s.append_integer (max_age)
|
s.append_integer (max_age)
|
||||||
end
|
end
|
||||||
@@ -339,7 +343,7 @@ feature {NONE} -- Constants
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2015, Jocelyn Fiat, Eiffel Software and others"
|
copyright: "2011-2016, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -180,7 +180,9 @@ feature -- Header: adding
|
|||||||
if line [line.count] = '%R' then
|
if line [line.count] = '%R' then
|
||||||
line.remove_tail (1)
|
line.remove_tail (1)
|
||||||
end
|
end
|
||||||
add_header (line)
|
if not line.is_empty then
|
||||||
|
add_header (line)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ feature -- Test routines
|
|||||||
l_cookie: HTTP_COOKIE
|
l_cookie: HTTP_COOKIE
|
||||||
do
|
do
|
||||||
create l_cookie.make ("user_id", "u12345")
|
create l_cookie.make ("user_id", "u12345")
|
||||||
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Max-Age=-1"))
|
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345"))
|
||||||
end
|
end
|
||||||
|
|
||||||
test_cookie_value_with_illegal_characters
|
test_cookie_value_with_illegal_characters
|
||||||
@@ -42,7 +42,7 @@ feature -- Test routines
|
|||||||
l_cookie: HTTP_COOKIE
|
l_cookie: HTTP_COOKIE
|
||||||
do
|
do
|
||||||
create l_cookie.make ("user_id", "")
|
create l_cookie.make ("user_id", "")
|
||||||
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=; Max-Age=-1"))
|
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id="))
|
||||||
end
|
end
|
||||||
|
|
||||||
test_cookie_full_attributes
|
test_cookie_full_attributes
|
||||||
@@ -55,7 +55,8 @@ feature -- Test routines
|
|||||||
l_cookie.set_path ("/")
|
l_cookie.set_path ("/")
|
||||||
l_cookie.set_secure (True)
|
l_cookie.set_secure (True)
|
||||||
l_cookie.set_http_only (True)
|
l_cookie.set_http_only (True)
|
||||||
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Domain=www.example.com; Path=/; Expires=Sat, 18 Apr 2015 21:22:05 GMT; Max-Age=-1; Secure; HttpOnly"))
|
l_cookie.set_max_age (1)
|
||||||
|
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Domain=www.example.com; Path=/; Expires=Sat, 18 Apr 2015 21:22:05 GMT; Max-Age=1; Secure; HttpOnly"))
|
||||||
end
|
end
|
||||||
|
|
||||||
test_cookie_include_expires
|
test_cookie_include_expires
|
||||||
@@ -68,7 +69,6 @@ feature -- Test routines
|
|||||||
l_cookie.set_path ("/")
|
l_cookie.set_path ("/")
|
||||||
l_cookie.set_secure (True)
|
l_cookie.set_secure (True)
|
||||||
l_cookie.set_http_only (True)
|
l_cookie.set_http_only (True)
|
||||||
l_cookie.mark_expires
|
|
||||||
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Domain=www.example.com; Path=/; Expires=Sat, 18 Apr 2015 21:22:05 GMT; Secure; HttpOnly"))
|
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Domain=www.example.com; Path=/; Expires=Sat, 18 Apr 2015 21:22:05 GMT; Secure; HttpOnly"))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -82,8 +82,8 @@ feature -- Test routines
|
|||||||
l_cookie.set_path ("/")
|
l_cookie.set_path ("/")
|
||||||
l_cookie.set_secure (True)
|
l_cookie.set_secure (True)
|
||||||
l_cookie.set_http_only (True)
|
l_cookie.set_http_only (True)
|
||||||
l_cookie.mark_max_age
|
l_cookie.set_max_age (1)
|
||||||
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Domain=www.example.com; Path=/; Max-Age=-1; Secure; HttpOnly"))
|
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Domain=www.example.com; Path=/; Expires=Sat, 18 Apr 2015 21:22:05 GMT; Max-Age=1; Secure; HttpOnly"))
|
||||||
end
|
end
|
||||||
|
|
||||||
test_cookie_defaults_and_http_only
|
test_cookie_defaults_and_http_only
|
||||||
@@ -92,7 +92,7 @@ feature -- Test routines
|
|||||||
do
|
do
|
||||||
create l_cookie.make ("user_id", "u12345")
|
create l_cookie.make ("user_id", "u12345")
|
||||||
l_cookie.set_http_only (True)
|
l_cookie.set_http_only (True)
|
||||||
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Max-Age=-1; HttpOnly"))
|
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; HttpOnly"))
|
||||||
end
|
end
|
||||||
|
|
||||||
test_cookie_defaults_and_secure
|
test_cookie_defaults_and_secure
|
||||||
@@ -101,7 +101,7 @@ feature -- Test routines
|
|||||||
do
|
do
|
||||||
create l_cookie.make ("user_id", "u12345")
|
create l_cookie.make ("user_id", "u12345")
|
||||||
l_cookie.set_secure (True)
|
l_cookie.set_secure (True)
|
||||||
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Max-Age=-1; Secure"))
|
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Secure"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ feature -- Test routines
|
|||||||
do
|
do
|
||||||
create l_cookie.make ("user_id", "u12345")
|
create l_cookie.make ("user_id", "u12345")
|
||||||
l_cookie.set_domain ("www.example.com")
|
l_cookie.set_domain ("www.example.com")
|
||||||
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Domain=www.example.com; Max-Age=-1"))
|
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Domain=www.example.com"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ feature -- Test routines
|
|||||||
do
|
do
|
||||||
create l_cookie.make ("user_id", "u12345")
|
create l_cookie.make ("user_id", "u12345")
|
||||||
l_cookie.set_path ("/")
|
l_cookie.set_path ("/")
|
||||||
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Path=/; Max-Age=-1"))
|
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Path=/"))
|
||||||
end
|
end
|
||||||
|
|
||||||
test_cookie_default_and_custom_max_age
|
test_cookie_default_and_custom_max_age
|
||||||
@@ -149,6 +149,18 @@ feature -- Test routines
|
|||||||
assert ("Invalid RFC1123", not l_cookie.is_valid_rfc1123_date ("Thuesday, 19 Mar 2015 16:14:03 GMT"))
|
assert ("Invalid RFC1123", not l_cookie.is_valid_rfc1123_date ("Thuesday, 19 Mar 2015 16:14:03 GMT"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test_cookie_without_max_age_and_expires
|
||||||
|
local
|
||||||
|
l_cookie: HTTP_COOKIE
|
||||||
|
do
|
||||||
|
create l_cookie.make ("user_id", "u12345")
|
||||||
|
l_cookie.set_domain ("www.example.com")
|
||||||
|
l_cookie.set_path ("/")
|
||||||
|
l_cookie.set_secure (True)
|
||||||
|
l_cookie.set_http_only (True)
|
||||||
|
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Domain=www.example.com; Path=/; Secure; HttpOnly"))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,21 @@ project
|
|||||||
notification_email = "notification_email.ecf"
|
notification_email = "notification_email.ecf"
|
||||||
|
|
||||||
note
|
note
|
||||||
-- title:
|
title: Notification Email
|
||||||
-- description:
|
description: "[
|
||||||
-- tags:
|
Abstract interface to send message via various mailers:
|
||||||
-- license:
|
- smtp
|
||||||
-- copyright:
|
- sendmail
|
||||||
-- link[doc]: "Documentation" http://
|
- external script
|
||||||
|
- store on local file
|
||||||
|
- ...
|
||||||
|
]"
|
||||||
|
collection: EWF
|
||||||
|
tags: message,smtp,sendmail,mailer
|
||||||
|
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||||
|
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||||
|
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||||
|
link[source]: "github" https://github.com/EiffelWebFramework/EWF/tree/master/library/runtime/process/notification_email
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -508,9 +508,9 @@ feature -- Helper
|
|||||||
|
|
||||||
new_session (a_uri: READABLE_STRING_8): HTTP_CLIENT_SESSION
|
new_session (a_uri: READABLE_STRING_8): HTTP_CLIENT_SESSION
|
||||||
local
|
local
|
||||||
cl: LIBCURL_HTTP_CLIENT
|
cl: DEFAULT_HTTP_CLIENT
|
||||||
do
|
do
|
||||||
create cl.make
|
create cl
|
||||||
Result := cl.new_session (a_uri)
|
Result := cl.new_session (a_uri)
|
||||||
Result.set_is_insecure (True)
|
Result.set_is_insecure (True)
|
||||||
Result.set_max_redirects (5)
|
Result.set_max_redirects (5)
|
||||||
|
|||||||
@@ -3,14 +3,17 @@ package openid
|
|||||||
project
|
project
|
||||||
openid = "consumer/openid.ecf"
|
openid = "consumer/openid.ecf"
|
||||||
openid = "consumer/openid-safe.ecf"
|
openid = "consumer/openid-safe.ecf"
|
||||||
demo = "consumer/demo/demo-safe.ecf"
|
|
||||||
|
|
||||||
note
|
note
|
||||||
title: Eiffel OpenID
|
title: Eiffel OpenID
|
||||||
description: OpenID library (for now only consumer)
|
description: OpenID consumer library
|
||||||
tags: openid,security
|
tags: openid,security,web,authentication,sso
|
||||||
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||||
-- copyright:
|
copyright: 2011-2016, Jocelyn Fiat, Eiffel Software and others
|
||||||
-- link[doc]: "Documentation" http://
|
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||||
|
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||||
|
link[source]: "github" https://github.com/EiffelWebFramework/EWF/tree/master/library/security/http_authorization
|
||||||
|
link[doc]: "Documentation" https://github.com/EiffelWebFramework/EWF/tree/master/library/security/http_authorization/README.md
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,16 @@ project
|
|||||||
http_authorization = "http_authorization.ecf"
|
http_authorization = "http_authorization.ecf"
|
||||||
|
|
||||||
note
|
note
|
||||||
-- title:
|
title: HTTP Authorization
|
||||||
-- description:
|
description: "[
|
||||||
-- tags:
|
Class to manipulate HTTP 'Authorization' header value.
|
||||||
-- license:
|
]"
|
||||||
-- copyright:
|
collection: EWF
|
||||||
-- link[doc]: "Documentation" http://
|
tags: http,authorization,authentication,web
|
||||||
|
copyright: 2011-2016, Jocelyn Fiat, Eiffel Software and others
|
||||||
|
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||||
|
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||||
|
link[source]: "github" https://github.com/EiffelWebFramework/EWF/tree/master/library/server/authentication/http_authorization
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ feature {NONE} -- Initialization
|
|||||||
local
|
local
|
||||||
n: INTEGER
|
n: INTEGER
|
||||||
p: like pool
|
p: like pool
|
||||||
do
|
do
|
||||||
n := max_concurrent_connections (server)
|
n := max_concurrent_connections (server).max (1) -- At least one processor!
|
||||||
create p.make (n)
|
create p.make (n)
|
||||||
initialize_pool (p, n)
|
initialize_pool (p, n)
|
||||||
pool := p
|
pool := p
|
||||||
@@ -25,20 +25,27 @@ feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
|||||||
release
|
release
|
||||||
-- <Precursor>
|
-- <Precursor>
|
||||||
local
|
local
|
||||||
d: STRING
|
d: detachable STRING
|
||||||
do
|
do
|
||||||
if attached internal_client_socket as l_socket then
|
|
||||||
d := l_socket.descriptor.out
|
|
||||||
else
|
|
||||||
d := "N/A"
|
|
||||||
end
|
|
||||||
debug ("dbglog")
|
debug ("dbglog")
|
||||||
|
if
|
||||||
|
attached internal_client_socket as l_socket and then
|
||||||
|
l_socket.descriptor_available
|
||||||
|
then
|
||||||
|
d := l_socket.descriptor.out
|
||||||
|
else
|
||||||
|
d := "N/A"
|
||||||
|
end
|
||||||
dbglog (generator + ".release: ENTER {" + d + "}")
|
dbglog (generator + ".release: ENTER {" + d + "}")
|
||||||
end
|
end
|
||||||
Precursor {HTTPD_REQUEST_HANDLER_I}
|
Precursor {HTTPD_REQUEST_HANDLER_I}
|
||||||
release_pool_item
|
release_pool_item
|
||||||
debug ("dbglog")
|
debug ("dbglog")
|
||||||
dbglog (generator + ".release: LEAVE {" + d + "}")
|
if d /= Void then
|
||||||
|
dbglog (generator + ".release: LEAVE {" + d + "}")
|
||||||
|
else
|
||||||
|
dbglog (generator + ".release: LEAVE {N/A}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ feature {NONE} -- Initialization
|
|||||||
local
|
local
|
||||||
n: INTEGER
|
n: INTEGER
|
||||||
do
|
do
|
||||||
n := max_concurrent_connections (server)
|
n := max_concurrent_connections (server).max (1) -- At least one thread!
|
||||||
create pool.make (n.to_natural_32)
|
create pool.make (n.to_natural_32)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -18,21 +18,28 @@ inherit
|
|||||||
feature {HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
feature {HTTPD_CONNECTION_HANDLER_I} -- Basic operation
|
||||||
|
|
||||||
release
|
release
|
||||||
|
-- <Precursor>
|
||||||
local
|
local
|
||||||
d: STRING
|
d: detachable STRING
|
||||||
do
|
do
|
||||||
-- FIXME: for log purpose
|
|
||||||
if attached internal_client_socket as l_socket then
|
|
||||||
d := l_socket.descriptor.out
|
|
||||||
else
|
|
||||||
d := "N/A"
|
|
||||||
end
|
|
||||||
debug ("dbglog")
|
debug ("dbglog")
|
||||||
|
if
|
||||||
|
attached internal_client_socket as l_socket and then
|
||||||
|
l_socket.descriptor_available
|
||||||
|
then
|
||||||
|
d := l_socket.descriptor.out
|
||||||
|
else
|
||||||
|
d := "N/A"
|
||||||
|
end
|
||||||
dbglog (generator + ".release: ENTER {" + d + "}")
|
dbglog (generator + ".release: ENTER {" + d + "}")
|
||||||
end
|
end
|
||||||
Precursor {HTTPD_REQUEST_HANDLER_I}
|
Precursor {HTTPD_REQUEST_HANDLER_I}
|
||||||
debug ("dbglog")
|
debug ("dbglog")
|
||||||
dbglog (generator + ".release: LEAVE {" + d + "}")
|
if d /= Void then
|
||||||
|
dbglog (generator + ".release: LEAVE {" + d + "}")
|
||||||
|
else
|
||||||
|
dbglog (generator + ".release: LEAVE {N/A}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,348 @@
|
|||||||
|
note
|
||||||
|
description: "Configuration for the standalone HTTPd server."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
HTTPD_CONFIGURATION_I
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ANY
|
||||||
|
|
||||||
|
HTTPD_CONSTANTS
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make
|
||||||
|
do
|
||||||
|
http_server_port := default_http_server_port
|
||||||
|
max_concurrent_connections := default_max_concurrent_connections
|
||||||
|
max_tcp_clients := default_max_tcp_clients
|
||||||
|
socket_timeout := default_socket_timeout
|
||||||
|
socket_recv_timeout := default_socket_recv_timeout
|
||||||
|
keep_alive_timeout := default_keep_alive_timeout
|
||||||
|
max_keep_alive_requests := default_max_keep_alive_requests
|
||||||
|
is_secure := False
|
||||||
|
create ca_crt.make_empty
|
||||||
|
create ca_key.make_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
Server_details: STRING_8
|
||||||
|
-- Detail of the server.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
http_server_name: detachable READABLE_STRING_8 assign set_http_server_name
|
||||||
|
http_server_port: INTEGER assign set_http_server_port
|
||||||
|
max_tcp_clients: INTEGER assign set_max_tcp_clients
|
||||||
|
-- Listen on socket for at most `queue' connections.
|
||||||
|
|
||||||
|
socket_timeout: INTEGER assign set_socket_timeout
|
||||||
|
-- Amount of seconds that the server waits for receipts and transmissions during communications.
|
||||||
|
-- note: with timeout of 0, socket can wait for ever.
|
||||||
|
-- By default: 60 seconds, which is appropriate for most situations.
|
||||||
|
|
||||||
|
socket_recv_timeout: INTEGER assign set_socket_recv_timeout
|
||||||
|
-- Amount of seconds that the server waits for receiving data during communications.
|
||||||
|
-- note: with timeout of 0, socket can wait for ever.
|
||||||
|
-- By default: 5 seconds.
|
||||||
|
|
||||||
|
max_concurrent_connections: INTEGER assign set_max_concurrent_connections
|
||||||
|
-- Max number of concurrent connections.
|
||||||
|
|
||||||
|
force_single_threaded: BOOLEAN assign set_force_single_threaded
|
||||||
|
do
|
||||||
|
Result := max_concurrent_connections = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
is_verbose: BOOLEAN assign set_is_verbose
|
||||||
|
-- Display verbose message to the output?
|
||||||
|
|
||||||
|
verbose_level: INTEGER assign set_verbose_level
|
||||||
|
-- Verbosity of output.
|
||||||
|
|
||||||
|
keep_alive_timeout: INTEGER assign set_keep_alive_timeout
|
||||||
|
-- Persistent connection timeout.
|
||||||
|
-- Number of seconds the server waits after a request has been served before it closes the connection.
|
||||||
|
-- Timeout unit in Seconds.
|
||||||
|
-- By default: 5 seconds.
|
||||||
|
|
||||||
|
max_keep_alive_requests: INTEGER assign set_max_keep_alive_requests
|
||||||
|
-- Maximum number of requests allowed per persistent connection.
|
||||||
|
-- Recommended a high setting.
|
||||||
|
-- To disable KeepAlive, set `max_keep_alive_requests' to 0.
|
||||||
|
-- By default: 100 .
|
||||||
|
|
||||||
|
has_ssl_support: BOOLEAN
|
||||||
|
-- Has SSL support?
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
request_settings: HTTPD_REQUEST_SETTINGS
|
||||||
|
do
|
||||||
|
Result.is_verbose := is_verbose
|
||||||
|
Result.verbose_level := verbose_level
|
||||||
|
Result.timeout := socket_timeout
|
||||||
|
Result.socket_recv_timeout := socket_recv_timeout
|
||||||
|
Result.keep_alive_timeout := keep_alive_timeout
|
||||||
|
Result.max_keep_alive_requests := max_keep_alive_requests
|
||||||
|
Result.is_secure := is_secure
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access: SSL
|
||||||
|
|
||||||
|
is_secure: BOOLEAN
|
||||||
|
-- Is SSL/TLS session?.
|
||||||
|
|
||||||
|
ca_crt: detachable IMMUTABLE_STRING_32
|
||||||
|
-- the signed certificate.
|
||||||
|
|
||||||
|
ca_key: detachable IMMUTABLE_STRING_32
|
||||||
|
-- private key to the certificate.
|
||||||
|
|
||||||
|
ssl_protocol: NATURAL
|
||||||
|
-- By default protocol is tls 1.2.
|
||||||
|
|
||||||
|
feature -- Element change
|
||||||
|
|
||||||
|
set_ssl_settings (v: detachable separate TUPLE [protocol: separate READABLE_STRING_GENERAL; ca_crt, ca_key: detachable separate READABLE_STRING_GENERAL])
|
||||||
|
local
|
||||||
|
prot: STRING_32
|
||||||
|
do
|
||||||
|
is_secure := False
|
||||||
|
ca_crt := Void
|
||||||
|
ca_key := Void
|
||||||
|
if v /= Void then
|
||||||
|
is_secure := True
|
||||||
|
create prot.make_from_separate (v.protocol)
|
||||||
|
set_ssl_protocol_from_string (prot)
|
||||||
|
set_ca_crt (v.ca_crt)
|
||||||
|
set_ca_key (v.ca_key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
set_http_server_name (v: detachable separate READABLE_STRING_8)
|
||||||
|
do
|
||||||
|
if v = Void then
|
||||||
|
unset_http_server_name
|
||||||
|
else
|
||||||
|
create {IMMUTABLE_STRING_8} http_server_name.make_from_separate (v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
unset_http_server_name
|
||||||
|
-- Unset `http_server_name' value.
|
||||||
|
do
|
||||||
|
http_server_name := Void
|
||||||
|
ensure
|
||||||
|
unset_http_server_name: http_server_name = Void
|
||||||
|
end
|
||||||
|
|
||||||
|
set_http_server_port (v: like http_server_port)
|
||||||
|
-- Set `http_server_port' with `v'.
|
||||||
|
do
|
||||||
|
http_server_port := v
|
||||||
|
ensure
|
||||||
|
http_server_port_set: http_server_port = v
|
||||||
|
end
|
||||||
|
|
||||||
|
set_max_tcp_clients (v: like max_tcp_clients)
|
||||||
|
-- Set `max_tcp_clients' with `v'.
|
||||||
|
do
|
||||||
|
max_tcp_clients := v
|
||||||
|
ensure
|
||||||
|
max_tcp_clients_set: max_tcp_clients = v
|
||||||
|
end
|
||||||
|
|
||||||
|
set_max_concurrent_connections (v: like max_concurrent_connections)
|
||||||
|
-- Set `max_concurrent_connections' with `v'.
|
||||||
|
do
|
||||||
|
max_concurrent_connections := v
|
||||||
|
ensure
|
||||||
|
max_concurrent_connections_set : max_concurrent_connections = v
|
||||||
|
end
|
||||||
|
|
||||||
|
set_socket_timeout (a_nb_seconds: like socket_timeout)
|
||||||
|
-- Set `socket_timeout' with `a_nb_seconds'
|
||||||
|
do
|
||||||
|
socket_timeout := a_nb_seconds
|
||||||
|
ensure
|
||||||
|
socket_timeout_set: socket_timeout = a_nb_seconds
|
||||||
|
end
|
||||||
|
|
||||||
|
set_socket_recv_timeout (a_nb_seconds: like socket_recv_timeout)
|
||||||
|
-- Set `socket_recv_timeout' with `a_nb_seconds'
|
||||||
|
do
|
||||||
|
socket_recv_timeout := a_nb_seconds
|
||||||
|
ensure
|
||||||
|
socket_recv_timeout_set: socket_recv_timeout = a_nb_seconds
|
||||||
|
end
|
||||||
|
|
||||||
|
set_keep_alive_timeout (a_seconds: like keep_alive_timeout)
|
||||||
|
-- Set `keep_alive_timeout' with `a_seconds'
|
||||||
|
do
|
||||||
|
keep_alive_timeout := a_seconds
|
||||||
|
ensure
|
||||||
|
keep_alive_timeout_set: keep_alive_timeout = a_seconds
|
||||||
|
end
|
||||||
|
|
||||||
|
set_max_keep_alive_requests (nb: like max_keep_alive_requests)
|
||||||
|
-- Set `max_keep_alive_requests' with `nb'
|
||||||
|
do
|
||||||
|
max_keep_alive_requests := nb
|
||||||
|
ensure
|
||||||
|
max_keep_alive_requests_set: max_keep_alive_requests = nb
|
||||||
|
end
|
||||||
|
|
||||||
|
set_force_single_threaded (v: like force_single_threaded)
|
||||||
|
-- Force server to handle incoming request in a single thread.
|
||||||
|
-- i.e set max_concurrent_connections to 0!
|
||||||
|
obsolete
|
||||||
|
"Use set_max_concurrent_connections (0) [June/2016]"
|
||||||
|
do
|
||||||
|
if v then
|
||||||
|
set_max_concurrent_connections (0)
|
||||||
|
end
|
||||||
|
--|Missing postcondition
|
||||||
|
--| force_single_thread_set: v implies max_concurrent_connections = 0
|
||||||
|
--| not_single_thread: not v implies max_concurrent_connections > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
set_is_verbose (b: BOOLEAN)
|
||||||
|
-- Set `is_verbose' to `b'
|
||||||
|
do
|
||||||
|
is_verbose := b
|
||||||
|
ensure
|
||||||
|
is_verbose_set: is_verbose = b
|
||||||
|
end
|
||||||
|
|
||||||
|
set_verbose_level (lev: INTEGER)
|
||||||
|
-- Set `verbose_level' to `lev'.
|
||||||
|
do
|
||||||
|
verbose_level := lev
|
||||||
|
ensure
|
||||||
|
verbose_level_set: verbose_level = lev
|
||||||
|
end
|
||||||
|
|
||||||
|
set_is_secure (b: BOOLEAN)
|
||||||
|
-- Set `is_secure' to `b'.
|
||||||
|
do
|
||||||
|
if b and has_ssl_support then
|
||||||
|
is_secure := True
|
||||||
|
if
|
||||||
|
http_server_port = 80
|
||||||
|
then
|
||||||
|
set_http_server_port (443)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
is_secure := False
|
||||||
|
if
|
||||||
|
http_server_port = 443
|
||||||
|
then
|
||||||
|
set_http_server_port (80)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
is_secure_set: has_ssl_support implies is_secure
|
||||||
|
is_not_secure: not has_ssl_support implies not is_secure
|
||||||
|
end
|
||||||
|
|
||||||
|
mark_secure
|
||||||
|
-- Set is_secure in True
|
||||||
|
do
|
||||||
|
set_is_secure (True)
|
||||||
|
ensure
|
||||||
|
is_secure_set: has_ssl_support implies is_secure
|
||||||
|
-- http_server_port_set: has_ssl_support implies http_server_port = 443
|
||||||
|
is_not_secure: not has_ssl_support implies not is_secure
|
||||||
|
-- default_port: not has_ssl_support implies http_server_port = 80
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Element change
|
||||||
|
|
||||||
|
set_ca_crt (a_value: detachable separate READABLE_STRING_GENERAL)
|
||||||
|
-- Set `ca_crt' from `a_value'.
|
||||||
|
do
|
||||||
|
if a_value /= Void then
|
||||||
|
create ca_crt.make_from_separate (a_value)
|
||||||
|
else
|
||||||
|
ca_crt := Void
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
set_ca_key (a_value: detachable separate READABLE_STRING_GENERAL)
|
||||||
|
-- Set `ca_key' with `a_value'.
|
||||||
|
do
|
||||||
|
if a_value /= Void then
|
||||||
|
create ca_key.make_from_separate (a_value)
|
||||||
|
else
|
||||||
|
ca_key := Void
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
set_ssl_protocol (a_version: NATURAL)
|
||||||
|
-- Set `ssl_protocol' with `a_version'
|
||||||
|
do
|
||||||
|
ssl_protocol := a_version
|
||||||
|
ensure
|
||||||
|
ssl_protocol_set: ssl_protocol = a_version
|
||||||
|
end
|
||||||
|
|
||||||
|
set_ssl_protocol_from_string (a_ssl_version: READABLE_STRING_GENERAL)
|
||||||
|
-- Set `ssl_protocol' with `a_ssl_version'
|
||||||
|
do
|
||||||
|
if a_ssl_version.is_case_insensitive_equal ("ssl_2_3") then
|
||||||
|
set_ssl_protocol_to_ssl_2_or_3
|
||||||
|
elseif a_ssl_version.is_case_insensitive_equal ("tls_1_0") then
|
||||||
|
set_ssl_protocol_to_tls_1_0
|
||||||
|
elseif a_ssl_version.is_case_insensitive_equal ("tls_1_1") then
|
||||||
|
set_ssl_protocol_to_tls_1_1
|
||||||
|
elseif a_ssl_version.is_case_insensitive_equal ("tls_1_2") then
|
||||||
|
set_ssl_protocol_to_tls_1_2
|
||||||
|
elseif a_ssl_version.is_case_insensitive_equal ("dtls_1_0") then
|
||||||
|
set_ssl_protocol_to_dtls_1_0
|
||||||
|
else -- Default
|
||||||
|
set_ssl_protocol_to_tls_1_2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- SSL Helpers
|
||||||
|
|
||||||
|
set_ssl_protocol_to_ssl_2_or_3
|
||||||
|
-- Set `ssl_protocol' with `Ssl_23'.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
set_ssl_protocol_to_tls_1_0
|
||||||
|
-- Set `ssl_protocol' with `Tls_1_0'.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
set_ssl_protocol_to_tls_1_1
|
||||||
|
-- Set `ssl_protocol' with `Tls_1_1'.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
set_ssl_protocol_to_tls_1_2
|
||||||
|
-- Set `ssl_protocol' with `Tls_1_2'.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
set_ssl_protocol_to_dtls_1_0
|
||||||
|
-- Set `ssl_protocol' with `Dtls_1_0'.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Various constant values used in httpd settings.
|
||||||
|
]"
|
||||||
|
author: "$Author$"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
HTTPD_CONSTANTS
|
||||||
|
|
||||||
|
feature -- Default connection settings
|
||||||
|
|
||||||
|
default_http_server_port: INTEGER = 80
|
||||||
|
default_max_concurrent_connections: INTEGER = 100
|
||||||
|
default_max_tcp_clients: INTEGER = 100
|
||||||
|
|
||||||
|
feature -- Default timeout settings
|
||||||
|
|
||||||
|
default_socket_timeout: INTEGER = 60 -- seconds
|
||||||
|
default_socket_recv_timeout: INTEGER = 5 -- seconds
|
||||||
|
|
||||||
|
feature -- Default persistent connection settings
|
||||||
|
|
||||||
|
default_keep_alive_timeout: INTEGER = 15 -- seconds
|
||||||
|
default_max_keep_alive_requests: INTEGER = 100
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Request settings for the standalone HTTPd server.
|
||||||
|
]"
|
||||||
|
author: "$Author$"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
expanded class
|
||||||
|
HTTPD_REQUEST_SETTINGS
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
is_verbose: BOOLEAN assign set_is_verbose
|
||||||
|
-- Is verbose?
|
||||||
|
|
||||||
|
verbose_level: INTEGER assign set_verbose_level
|
||||||
|
-- Verbosity of output.
|
||||||
|
|
||||||
|
is_secure: BOOLEAN assign set_is_secure
|
||||||
|
-- Is using secure connection? i.e SSL?
|
||||||
|
|
||||||
|
timeout: INTEGER assign set_timeout
|
||||||
|
-- Amount of seconds that the server waits for receipts and transmissions during communications.
|
||||||
|
|
||||||
|
socket_recv_timeout: INTEGER assign set_socket_recv_timeout
|
||||||
|
-- Amount of seconds that the server waits for receiving data on socket during communications.
|
||||||
|
|
||||||
|
keep_alive_timeout: INTEGER assign set_keep_alive_timeout
|
||||||
|
-- Keep-alive timeout, also known as persistent-connection timeout.
|
||||||
|
-- Number of seconds the server waits after a request has been served before it closes the connection.
|
||||||
|
-- Unit in Seconds.
|
||||||
|
|
||||||
|
max_keep_alive_requests: INTEGER assign set_max_keep_alive_requests
|
||||||
|
-- Maximum number of requests allowed per persistent connection.
|
||||||
|
|
||||||
|
feature -- Change
|
||||||
|
|
||||||
|
set_is_verbose (b: BOOLEAN)
|
||||||
|
-- Set `is_verbose' to `b'.
|
||||||
|
do
|
||||||
|
is_verbose := b
|
||||||
|
end
|
||||||
|
|
||||||
|
set_verbose_level (lev: INTEGER)
|
||||||
|
-- Set `verbose_level' to `lev'.
|
||||||
|
do
|
||||||
|
verbose_level := lev
|
||||||
|
end
|
||||||
|
|
||||||
|
set_is_secure (b: BOOLEAN)
|
||||||
|
-- Set `is_secure' to `b'.
|
||||||
|
do
|
||||||
|
is_secure := b
|
||||||
|
end
|
||||||
|
|
||||||
|
set_timeout (a_timeout_in_seconds: INTEGER)
|
||||||
|
-- Set `timeout' to `a_timeout_in_seconds'.
|
||||||
|
do
|
||||||
|
timeout := a_timeout_in_seconds
|
||||||
|
end
|
||||||
|
|
||||||
|
set_socket_recv_timeout (a_timeout_in_seconds: INTEGER)
|
||||||
|
-- Set `socket_recv_timeout' to `a_timeout_in_seconds'.
|
||||||
|
do
|
||||||
|
socket_recv_timeout := a_timeout_in_seconds
|
||||||
|
end
|
||||||
|
|
||||||
|
set_keep_alive_timeout (a_timeout_in_seconds: INTEGER)
|
||||||
|
-- Set `keep_alive_timeout' to `a_timeout_in_seconds'.
|
||||||
|
do
|
||||||
|
keep_alive_timeout := a_timeout_in_seconds
|
||||||
|
end
|
||||||
|
|
||||||
|
set_max_keep_alive_requests (nb: like max_keep_alive_requests)
|
||||||
|
-- Set `max_keep_alive_requests' with `nb'
|
||||||
|
do
|
||||||
|
max_keep_alive_requests := nb
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="http_network" uuid="56DAA1CE-0A2E-451A-BFC9-7821578E79F0" library_target="http_network">
|
||||||
|
<target name="http_network">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="standard">
|
||||||
|
<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="net" location="$ISE_LIBRARY\library\net\net-safe.ecf" readonly="false"/>
|
||||||
|
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl-safe.ecf">
|
||||||
|
<condition>
|
||||||
|
<custom name="net_ssl_enabled" value="true"/>
|
||||||
|
</condition>
|
||||||
|
</library>
|
||||||
|
<cluster name="network" location=".\network\">
|
||||||
|
<cluster name="ssl_network" location="$|ssl\" recursive="true">
|
||||||
|
<condition>
|
||||||
|
<custom name="net_ssl_enabled" value="true"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
<cluster name="network_until_16_05" location="$|until_16_05\">
|
||||||
|
<condition>
|
||||||
|
<version type="compiler" max="16.11.0.0"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
<cluster name="network_from_16_11" location="$|from_16_11\">
|
||||||
|
<condition>
|
||||||
|
<version type="compiler" min="16.11.0.0"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
</cluster>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="http_network" uuid="56DAA1CE-0A2E-451A-BFC9-7821578E79F0" library_target="http_network">
|
||||||
|
<target name="http_network">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="false" void_safety="none" syntax="standard">
|
||||||
|
<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.ecf"/>
|
||||||
|
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
||||||
|
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl.ecf">
|
||||||
|
<condition>
|
||||||
|
<custom name="net_ssl_enabled" value="true"/>
|
||||||
|
</condition>
|
||||||
|
</library>
|
||||||
|
<cluster name="network" location=".\network\">
|
||||||
|
<cluster name="ssl_network" location="$|ssl\" recursive="true">
|
||||||
|
<condition>
|
||||||
|
<custom name="net_ssl_enabled" value="true"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
<cluster name="network_until_16_05" location="$|until_16_05\">
|
||||||
|
<condition>
|
||||||
|
<version type="compiler" max="16.11.0.0"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
<cluster name="network_from_16_11" location="$|from_16_11\">
|
||||||
|
<condition>
|
||||||
|
<version type="compiler" min="16.11.0.0"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
</cluster>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -24,11 +24,29 @@
|
|||||||
</condition>
|
</condition>
|
||||||
</library>
|
</library>
|
||||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||||
|
<cluster name="network" location=".\network" recursive="false">
|
||||||
|
<cluster name="ssl_network" location="$|ssl" recursive="true">
|
||||||
|
<condition>
|
||||||
|
<custom name="httpd_ssl_enabled" value="true"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
<cluster name="network_until_16_05" location="$|until_16_05\">
|
||||||
|
<condition>
|
||||||
|
<version type="compiler" max="16.11.0.0"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
<cluster name="network_from_16_11" location="$|from_16_11\">
|
||||||
|
<condition>
|
||||||
|
<version type="compiler" min="16.11.0.0"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
</cluster>
|
||||||
<cluster name="httpd_server" location=".\" recursive="true">
|
<cluster name="httpd_server" location=".\" recursive="true">
|
||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>/concurrency$</exclude>
|
<exclude>/concurrency$</exclude>
|
||||||
<exclude>/no_ssl$</exclude>
|
<exclude>/no_ssl$</exclude>
|
||||||
<exclude>/ssl$</exclude>
|
<exclude>/ssl$</exclude>
|
||||||
|
<exclude>/network$</exclude>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<cluster name="no_ssl" location="$|no_ssl\" recursive="true">
|
<cluster name="no_ssl" location="$|no_ssl\" recursive="true">
|
||||||
<condition>
|
<condition>
|
||||||
@@ -11,7 +11,6 @@
|
|||||||
</option>
|
</option>
|
||||||
<setting name="concurrency" value="thread"/>
|
<setting name="concurrency" value="thread"/>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder.ecf"/>
|
|
||||||
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
||||||
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl.ecf">
|
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl.ecf">
|
||||||
<condition>
|
<condition>
|
||||||
@@ -24,12 +23,29 @@
|
|||||||
</condition>
|
</condition>
|
||||||
</library>
|
</library>
|
||||||
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||||
|
<cluster name="network" location=".\network" recursive="false">
|
||||||
|
<cluster name="ssl_network" location="$|ssl" recursive="true">
|
||||||
|
<condition>
|
||||||
|
<custom name="httpd_ssl_enabled" value="true"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
<cluster name="network_until_16_05" location="$|until_16_05\">
|
||||||
|
<condition>
|
||||||
|
<version type="compiler" max="16.11.0.0"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
<cluster name="network_from_16_11" location="$|from_16_11\">
|
||||||
|
<condition>
|
||||||
|
<version type="compiler" min="16.11.0.0"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
</cluster>
|
||||||
<cluster name="httpd_server" location=".\" recursive="true">
|
<cluster name="httpd_server" location=".\" recursive="true">
|
||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>/EIFGENs$</exclude>
|
|
||||||
<exclude>/concurrency$</exclude>
|
<exclude>/concurrency$</exclude>
|
||||||
<exclude>/no_ssl$</exclude>
|
<exclude>/no_ssl$</exclude>
|
||||||
<exclude>/ssl$</exclude>
|
<exclude>/ssl$</exclude>
|
||||||
|
<exclude>/network$</exclude>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<cluster name="no_ssl" location="$|no_ssl\" recursive="true">
|
<cluster name="no_ssl" location="$|no_ssl\" recursive="true">
|
||||||
<condition>
|
<condition>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Constant value to define the logging level.
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
HTTPD_LOGGER_CONSTANTS
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
alert_level: INTEGER = 1 -- 0000 0001
|
||||||
|
critical_level: INTEGER = 2 -- 0000 0010
|
||||||
|
error_level: INTEGER = 4 -- 0000 0100
|
||||||
|
warning_level: INTEGER = 8 -- 0000 1000
|
||||||
|
|
||||||
|
notice_level: INTEGER = 16 -- 0001 0000
|
||||||
|
information_level: INTEGER = 32 -- 0010 0000
|
||||||
|
debug_level: INTEGER = 64 -- 0100 0000
|
||||||
|
|
||||||
|
end
|
||||||
@@ -9,11 +9,24 @@ deferred class
|
|||||||
inherit
|
inherit
|
||||||
HTTPD_DEBUG_FACILITIES
|
HTTPD_DEBUG_FACILITIES
|
||||||
|
|
||||||
|
HTTPD_LOGGER_CONSTANTS
|
||||||
|
|
||||||
|
HTTPD_SOCKET_FACTORY
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
make
|
make (a_request_settings: HTTPD_REQUEST_SETTINGS)
|
||||||
do
|
do
|
||||||
reset
|
reset
|
||||||
|
-- Import global request settings.
|
||||||
|
timeout := a_request_settings.timeout -- seconds
|
||||||
|
socket_recv_timeout := a_request_settings.socket_recv_timeout -- seconds
|
||||||
|
keep_alive_timeout := a_request_settings.keep_alive_timeout -- seconds
|
||||||
|
max_keep_alive_requests := a_request_settings.max_keep_alive_requests
|
||||||
|
|
||||||
|
is_verbose := a_request_settings.is_verbose
|
||||||
|
verbose_level := a_request_settings.verbose_level
|
||||||
|
is_secure := a_request_settings.is_secure
|
||||||
end
|
end
|
||||||
|
|
||||||
reset
|
reset
|
||||||
@@ -59,7 +72,7 @@ feature -- Access
|
|||||||
do
|
do
|
||||||
s := internal_client_socket
|
s := internal_client_socket
|
||||||
if s = Void then
|
if s = Void then
|
||||||
create s.make_empty
|
s := new_client_socket (is_secure)
|
||||||
internal_client_socket := s
|
internal_client_socket := s
|
||||||
end
|
end
|
||||||
Result := s
|
Result := s
|
||||||
@@ -107,16 +120,36 @@ feature -- Access
|
|||||||
feature -- Settings
|
feature -- Settings
|
||||||
|
|
||||||
is_verbose: BOOLEAN
|
is_verbose: BOOLEAN
|
||||||
|
-- Output messages?
|
||||||
|
|
||||||
|
verbose_level: INTEGER
|
||||||
|
-- Output verbosity.
|
||||||
|
|
||||||
|
is_secure: BOOLEAN
|
||||||
|
-- Is secure socket?
|
||||||
|
-- i.e: SSL?
|
||||||
|
|
||||||
is_persistent_connection_supported: BOOLEAN
|
is_persistent_connection_supported: BOOLEAN
|
||||||
-- Is persistent connection supported?
|
-- Is persistent connection supported?
|
||||||
do
|
do
|
||||||
Result := {HTTPD_SERVER}.is_persistent_connection_supported
|
Result := {HTTPD_SERVER}.is_persistent_connection_supported and then max_keep_alive_requests > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
persistent_connection_timeout: INTEGER = 5 -- seconds
|
is_next_persistent_connection_supported: BOOLEAN
|
||||||
|
-- Is next persistent connection supported?
|
||||||
|
-- note: it is relevant only if `is_persistent_connection_supported' is True.
|
||||||
|
|
||||||
|
timeout: INTEGER -- seconds
|
||||||
|
-- Amount of seconds that the server waits for receipts and transmissions during communications.
|
||||||
|
|
||||||
|
socket_recv_timeout: INTEGER -- seconds
|
||||||
|
-- Amount of seconds that the server waits for receiving data on socket during communications.
|
||||||
|
|
||||||
|
max_keep_alive_requests: INTEGER
|
||||||
|
-- Maximum number of requests allowed per persistent connection.
|
||||||
|
|
||||||
|
keep_alive_timeout: INTEGER -- seconds
|
||||||
-- Number of seconds for persistent connection timeout.
|
-- Number of seconds for persistent connection timeout.
|
||||||
-- Default: 5 sec.
|
|
||||||
|
|
||||||
feature -- Status report
|
feature -- Status report
|
||||||
|
|
||||||
@@ -162,9 +195,10 @@ feature -- Execution
|
|||||||
local
|
local
|
||||||
l_socket: like client_socket
|
l_socket: like client_socket
|
||||||
l_exit: BOOLEAN
|
l_exit: BOOLEAN
|
||||||
n: INTEGER
|
n,m: INTEGER
|
||||||
do
|
do
|
||||||
l_socket := client_socket
|
l_socket := client_socket
|
||||||
|
l_socket.set_recv_timeout (socket_recv_timeout)
|
||||||
check
|
check
|
||||||
socket_attached: l_socket /= Void
|
socket_attached: l_socket /= Void
|
||||||
socket_valid: l_socket.is_open_read and then l_socket.is_open_write
|
socket_valid: l_socket.is_open_read and then l_socket.is_open_write
|
||||||
@@ -172,27 +206,40 @@ feature -- Execution
|
|||||||
from
|
from
|
||||||
-- Process persistent connection as long the socket is not closed.
|
-- Process persistent connection as long the socket is not closed.
|
||||||
n := 0
|
n := 0
|
||||||
|
m := max_keep_alive_requests
|
||||||
|
is_next_persistent_connection_supported := True
|
||||||
until
|
until
|
||||||
l_exit
|
l_exit
|
||||||
loop
|
loop
|
||||||
n := n + 1
|
n := n + 1
|
||||||
|
if n >= m then
|
||||||
|
is_next_persistent_connection_supported := False
|
||||||
|
elseif n > 1 and is_verbose then
|
||||||
|
log ("Reuse connection (" + n.out + ")", information_level)
|
||||||
|
end
|
||||||
-- FIXME: it seems to be called one more time, mostly to see this is done.
|
-- FIXME: it seems to be called one more time, mostly to see this is done.
|
||||||
execute_request
|
execute_request (n > 1)
|
||||||
l_exit := not is_persistent_connection_supported
|
l_exit := not is_persistent_connection_supported
|
||||||
or has_error or l_socket.is_closed or not l_socket.is_open_read
|
or not is_next_persistent_connection_supported -- related to `max_keep_alive_requests'
|
||||||
or not is_persistent_connection_requested
|
or not is_persistent_connection_requested
|
||||||
|
or has_error or l_socket.is_closed or not l_socket.is_open_read
|
||||||
reset_request
|
reset_request
|
||||||
end
|
end
|
||||||
|
if l_exit and has_error and not l_socket.is_closed then
|
||||||
|
l_socket.close
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
execute_request
|
execute_request (a_is_reusing_connection: BOOLEAN)
|
||||||
|
-- Execute http request, and if `a_is_reusing_connection' is True
|
||||||
|
-- the execution is reusing the persistent connection.
|
||||||
require
|
require
|
||||||
is_connected: is_connected
|
is_connected: is_connected
|
||||||
|
reuse_connection_when_possible: a_is_reusing_connection implies is_persistent_connection_supported
|
||||||
local
|
local
|
||||||
l_remote_info: detachable like remote_info
|
l_remote_info: detachable like remote_info
|
||||||
l_socket: like client_socket
|
l_socket: like client_socket
|
||||||
l_is_ready: BOOLEAN
|
l_is_ready: BOOLEAN
|
||||||
i: INTEGER
|
|
||||||
do
|
do
|
||||||
l_socket := client_socket
|
l_socket := client_socket
|
||||||
check
|
check
|
||||||
@@ -208,21 +255,16 @@ feature -- Execution
|
|||||||
dbglog (generator + ".execute_request socket=" + l_socket.descriptor.out + " ENTER")
|
dbglog (generator + ".execute_request socket=" + l_socket.descriptor.out + " ENTER")
|
||||||
end
|
end
|
||||||
|
|
||||||
--| TODO: add configuration options for socket timeout.
|
if a_is_reusing_connection then
|
||||||
--| set by default 5 seconds.
|
--| set by default 5 seconds.
|
||||||
-- l_socket.set_timeout (persistent_connection_timeout) -- 5 seconds!
|
l_socket.set_recv_timeout (keep_alive_timeout) -- in seconds!
|
||||||
l_socket.set_timeout (1) -- 1 second!
|
|
||||||
from
|
|
||||||
i := persistent_connection_timeout -- * 1 sec
|
|
||||||
until
|
|
||||||
l_is_ready or i <= 0 or has_error
|
|
||||||
loop
|
|
||||||
l_is_ready := l_socket.ready_for_reading
|
l_is_ready := l_socket.ready_for_reading
|
||||||
check not l_socket.is_closed end
|
else
|
||||||
i := i - 1
|
l_is_ready := True
|
||||||
end
|
end
|
||||||
|
|
||||||
if l_is_ready then
|
if l_is_ready then
|
||||||
|
l_socket.set_recv_timeout (socket_recv_timeout) -- FIXME: return a 408 Request Timeout response ..
|
||||||
create l_remote_info
|
create l_remote_info
|
||||||
if attached l_socket.peer_address as l_addr then
|
if attached l_socket.peer_address as l_addr then
|
||||||
l_remote_info.addr := l_addr.host_address.host_address
|
l_remote_info.addr := l_addr.host_address.host_address
|
||||||
@@ -242,10 +284,13 @@ feature -- Execution
|
|||||||
if l_is_ready then
|
if l_is_ready then
|
||||||
-- check catch_bad_incoming_connection: False end
|
-- check catch_bad_incoming_connection: False end
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
log ("ERROR: invalid HTTP incoming request")
|
log (request_header + "%NWARNING: invalid HTTP incoming request", warning_level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
if is_verbose then
|
||||||
|
log (request_header, information_level)
|
||||||
|
end
|
||||||
process_request (l_socket)
|
process_request (l_socket)
|
||||||
end
|
end
|
||||||
debug ("dbglog")
|
debug ("dbglog")
|
||||||
@@ -289,7 +334,12 @@ feature -- Parsing
|
|||||||
do
|
do
|
||||||
create txt.make (64)
|
create txt.make (64)
|
||||||
request_header := txt
|
request_header := txt
|
||||||
if a_socket.is_readable and then attached next_line (a_socket) as l_request_line and then not l_request_line.is_empty then
|
if
|
||||||
|
not has_error and then
|
||||||
|
a_socket.is_readable and then
|
||||||
|
attached next_line (a_socket) as l_request_line and then
|
||||||
|
not l_request_line.is_empty
|
||||||
|
then
|
||||||
txt.append (l_request_line)
|
txt.append (l_request_line)
|
||||||
txt.append_character ('%N')
|
txt.append_character ('%N')
|
||||||
analyze_request_line (l_request_line)
|
analyze_request_line (l_request_line)
|
||||||
@@ -297,16 +347,17 @@ feature -- Parsing
|
|||||||
has_error := True
|
has_error := True
|
||||||
end
|
end
|
||||||
l_is_verbose := is_verbose
|
l_is_verbose := is_verbose
|
||||||
if not has_error or l_is_verbose then
|
if not has_error then
|
||||||
-- if `is_verbose' we can try to print the request, even if it is a bad HTTP request
|
|
||||||
from
|
from
|
||||||
line := next_line (a_socket)
|
line := next_line (a_socket)
|
||||||
until
|
until
|
||||||
line = Void or end_of_stream
|
line = Void or end_of_stream or has_error
|
||||||
loop
|
loop
|
||||||
n := line.count
|
n := line.count
|
||||||
if l_is_verbose then
|
debug ("ew_standalone")
|
||||||
log (line)
|
if l_is_verbose then
|
||||||
|
log (line, debug_level)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
pos := line.index_of (':', 1)
|
pos := line.index_of (':', 1)
|
||||||
if pos > 0 then
|
if pos > 0 then
|
||||||
@@ -353,9 +404,11 @@ feature -- Parsing
|
|||||||
local
|
local
|
||||||
n, pos, next_pos: INTEGER
|
n, pos, next_pos: INTEGER
|
||||||
do
|
do
|
||||||
if is_verbose then
|
debug ("ew_standalone")
|
||||||
log ("%N## Parse HTTP request line ##")
|
if is_verbose then
|
||||||
log (line)
|
log ("%N## Parse HTTP request line ##", debug_level)
|
||||||
|
log (line, debug_level)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
pos := line.index_of (' ', 1)
|
pos := line.index_of (' ', 1)
|
||||||
method := line.substring (1, pos - 1)
|
method := line.substring (1, pos - 1)
|
||||||
@@ -372,15 +425,31 @@ feature -- Parsing
|
|||||||
next_line (a_socket: HTTPD_STREAM_SOCKET): detachable STRING
|
next_line (a_socket: HTTPD_STREAM_SOCKET): detachable STRING
|
||||||
-- Next line fetched from `a_socket' is available.
|
-- Next line fetched from `a_socket' is available.
|
||||||
require
|
require
|
||||||
|
not_has_error: not has_error or is_verbose
|
||||||
is_readable: a_socket.is_open_read
|
is_readable: a_socket.is_open_read
|
||||||
local
|
local
|
||||||
retried: BOOLEAN
|
retried: BOOLEAN
|
||||||
do
|
do
|
||||||
if retried then
|
if retried then
|
||||||
|
has_error := True
|
||||||
Result := Void
|
Result := Void
|
||||||
elseif a_socket.socket_ok then
|
elseif a_socket.readable then
|
||||||
a_socket.read_line_thread_aware
|
a_socket.read_line_thread_aware
|
||||||
Result := a_socket.last_string
|
Result := a_socket.last_string
|
||||||
|
-- Do no check `socket_ok' before socket operation,
|
||||||
|
-- otherwise it may be False, due to error during other socket operation in same thread.
|
||||||
|
if not a_socket.socket_ok then
|
||||||
|
has_error := True
|
||||||
|
if is_verbose then
|
||||||
|
log (request_header +"%N" + Result + "%N## socket_ok=False! ##", debug_level)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Error with socket...
|
||||||
|
has_error := True
|
||||||
|
if is_verbose then
|
||||||
|
log (request_header + "%N## Socket is not readable! ##", debug_level)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
rescue
|
rescue
|
||||||
retried := True
|
retried := True
|
||||||
@@ -399,13 +468,17 @@ feature -- Output
|
|||||||
logger_set: logger = a_logger
|
logger_set: logger = a_logger
|
||||||
end
|
end
|
||||||
|
|
||||||
log (m: STRING)
|
log (m: STRING; a_level: INTEGER)
|
||||||
-- Log message `m'.
|
-- Log message `m'.
|
||||||
|
require
|
||||||
|
is_verbose: is_verbose
|
||||||
do
|
do
|
||||||
if attached logger as l_logger then
|
if is_verbose and (verbose_level & a_level) = a_level then
|
||||||
l_logger.log (m)
|
if attached logger as l_logger then
|
||||||
else
|
l_logger.log (m)
|
||||||
io.put_string (m + "%N")
|
else
|
||||||
|
io.put_string (m + "%N")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ feature {NONE} -- Initialization
|
|||||||
build_controller
|
build_controller
|
||||||
-- Build `controller'.
|
-- Build `controller'.
|
||||||
do
|
do
|
||||||
create controller
|
create <NONE> controller
|
||||||
end
|
end
|
||||||
|
|
||||||
initialize
|
initialize
|
||||||
@@ -51,6 +51,9 @@ feature -- Access
|
|||||||
is_verbose: BOOLEAN
|
is_verbose: BOOLEAN
|
||||||
-- Is verbose for output messages.
|
-- Is verbose for output messages.
|
||||||
|
|
||||||
|
verbose_level: INTEGER
|
||||||
|
-- Verbosity of output.
|
||||||
|
|
||||||
configuration: HTTPD_CONFIGURATION
|
configuration: HTTPD_CONFIGURATION
|
||||||
-- Associated server configuration.
|
-- Associated server configuration.
|
||||||
|
|
||||||
@@ -100,7 +103,17 @@ feature -- Execution
|
|||||||
apply_configuration
|
apply_configuration
|
||||||
is_terminated := False
|
is_terminated := False
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
log ("%N%NStarting Web Application Server (port=" + configuration.http_server_port.out + "):%N")
|
log ("%N%NStarting Web Application Server ...")
|
||||||
|
log (" - port = " + configuration.http_server_port.out)
|
||||||
|
log (" - max_tcp_clients = " + configuration.max_tcp_clients.out)
|
||||||
|
log (" - max_concurrent_connections = " + configuration.max_concurrent_connections.out)
|
||||||
|
log (" - socket_timeout = " + configuration.socket_timeout.out + " seconds")
|
||||||
|
log (" - socket_recv_timeout = " + configuration.socket_recv_timeout.out + " seconds")
|
||||||
|
log (" - keep_alive_timeout = " + configuration.keep_alive_timeout.out + " seconds")
|
||||||
|
log (" - max_keep_alive_requests = " + configuration.max_keep_alive_requests.out)
|
||||||
|
if configuration.verbose_level > 0 then
|
||||||
|
log (" - verbose_level = " + configuration.verbose_level.out)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
is_shutdown_requested := False
|
is_shutdown_requested := False
|
||||||
listen
|
listen
|
||||||
@@ -150,7 +163,7 @@ feature -- Listening
|
|||||||
|
|
||||||
if not l_listening_socket.is_bound then
|
if not l_listening_socket.is_bound then
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
log ("Socket could not be bound on port " + l_http_port.out)
|
log ("Socket could not be bound on port " + l_http_port.out + " !")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
l_http_port := l_listening_socket.port
|
l_http_port := l_listening_socket.port
|
||||||
@@ -159,9 +172,9 @@ feature -- Listening
|
|||||||
l_listening_socket.listen (configuration.max_tcp_clients)
|
l_listening_socket.listen (configuration.max_tcp_clients)
|
||||||
if is_verbose then
|
if is_verbose then
|
||||||
if configuration.is_secure then
|
if configuration.is_secure then
|
||||||
log ("%NHTTP Connection Server ready on port " + l_http_port.out +" : https://localhost:" + l_http_port.out + "/")
|
log ("%NListening on port " + l_http_port.out +" : https://localhost:" + l_http_port.out + "/")
|
||||||
else
|
else
|
||||||
log ("%NHTTP Connection Server ready on port " + l_http_port.out +" : http://localhost:" + l_http_port.out + "/")
|
log ("%NListening on port " + l_http_port.out +" : http://localhost:" + l_http_port.out + "/")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
on_launched (l_http_port)
|
on_launched (l_http_port)
|
||||||
@@ -312,6 +325,7 @@ feature -- Configuration change
|
|||||||
is_not_launched: not is_launched
|
is_not_launched: not is_launched
|
||||||
do
|
do
|
||||||
is_verbose := configuration.is_verbose
|
is_verbose := configuration.is_verbose
|
||||||
|
verbose_level := configuration.verbose_level
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Output
|
feature -- Output
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Since 16.11, the EiffelNet socket interface has recv_timeout and send_timeout.
|
||||||
|
]"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
TCP_STREAM_SOCKET_EXT
|
||||||
|
|
||||||
|
end
|
||||||
@@ -12,6 +12,8 @@ class
|
|||||||
create
|
create
|
||||||
make_server_by_address_and_port,
|
make_server_by_address_and_port,
|
||||||
make_server_by_port,
|
make_server_by_port,
|
||||||
|
make_client_by_address_and_port,
|
||||||
|
make_client_by_port,
|
||||||
make_from_separate,
|
make_from_separate,
|
||||||
make_empty
|
make_empty
|
||||||
|
|
||||||
@@ -30,6 +32,16 @@ feature {NONE} -- Initialization
|
|||||||
create {TCP_STREAM_SOCKET} socket.make_server_by_port (a_port)
|
create {TCP_STREAM_SOCKET} socket.make_server_by_port (a_port)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
make_client_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER)
|
||||||
|
do
|
||||||
|
create {TCP_STREAM_SOCKET} socket.make_client_by_address_and_port (an_address, a_port)
|
||||||
|
end
|
||||||
|
|
||||||
|
make_client_by_port (a_peer_port: INTEGER; a_peer_host: STRING)
|
||||||
|
do
|
||||||
|
create {TCP_STREAM_SOCKET} socket.make_client_by_port (a_peer_port, a_peer_host)
|
||||||
|
end
|
||||||
|
|
||||||
make_from_separate (s: separate HTTPD_STREAM_SOCKET)
|
make_from_separate (s: separate HTTPD_STREAM_SOCKET)
|
||||||
require
|
require
|
||||||
descriptor_available: s.descriptor_available
|
descriptor_available: s.descriptor_available
|
||||||
@@ -50,6 +62,7 @@ feature {NONE} -- Initialization
|
|||||||
feature -- Change
|
feature -- Change
|
||||||
|
|
||||||
set_timeout (n: INTEGER)
|
set_timeout (n: INTEGER)
|
||||||
|
-- Set timeout to `n' seconds.
|
||||||
do
|
do
|
||||||
if attached {NETWORK_STREAM_SOCKET} socket as l_socket then
|
if attached {NETWORK_STREAM_SOCKET} socket as l_socket then
|
||||||
l_socket.set_timeout (n)
|
l_socket.set_timeout (n)
|
||||||
@@ -70,6 +83,22 @@ feature -- Change
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
set_recv_timeout (a_timeout_seconds: INTEGER)
|
||||||
|
-- Set the receive timeout in seconds on Current socket.
|
||||||
|
do
|
||||||
|
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
||||||
|
l_socket.set_recv_timeout (a_timeout_seconds)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
set_send_timeout (a_timeout_seconds: INTEGER)
|
||||||
|
-- Set the send timeout in seconds on Current socket.
|
||||||
|
do
|
||||||
|
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
||||||
|
l_socket.set_send_timeout (a_timeout_seconds)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
last_string: STRING
|
last_string: STRING
|
||||||
@@ -164,6 +193,11 @@ feature -- Status Report
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
exists: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := socket.exists
|
||||||
|
end
|
||||||
|
|
||||||
is_blocking: BOOLEAN
|
is_blocking: BOOLEAN
|
||||||
do
|
do
|
||||||
Result := socket.is_blocking
|
Result := socket.is_blocking
|
||||||
@@ -176,6 +210,13 @@ feature -- Status Report
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
is_connected: BOOLEAN
|
||||||
|
do
|
||||||
|
if attached {TCP_STREAM_SOCKET} socket as l_socket then
|
||||||
|
Result := l_socket.is_connected
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
is_created: BOOLEAN
|
is_created: BOOLEAN
|
||||||
do
|
do
|
||||||
if attached {NETWORK_SOCKET} socket as l_socket then
|
if attached {NETWORK_SOCKET} socket as l_socket then
|
||||||
@@ -220,6 +261,16 @@ feature -- Status Report
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
connect
|
||||||
|
do
|
||||||
|
socket.connect
|
||||||
|
end
|
||||||
|
|
||||||
|
close
|
||||||
|
do
|
||||||
|
socket.close
|
||||||
|
end
|
||||||
|
|
||||||
listen (a_queue: INTEGER)
|
listen (a_queue: INTEGER)
|
||||||
do
|
do
|
||||||
socket.listen (a_queue)
|
socket.listen (a_queue)
|
||||||
@@ -17,36 +17,66 @@ inherit
|
|||||||
ready_for_writing,
|
ready_for_writing,
|
||||||
ready_for_reading,
|
ready_for_reading,
|
||||||
try_ready_for_reading,
|
try_ready_for_reading,
|
||||||
put_readable_string_8
|
put_readable_string_8,
|
||||||
|
make_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
create
|
create
|
||||||
make_ssl_server_by_address_and_port, make_ssl_server_by_port,
|
make_ssl_server_by_address_and_port, make_ssl_server_by_port,
|
||||||
make_server_by_address_and_port, make_server_by_port
|
make_server_by_address_and_port, make_server_by_port,
|
||||||
|
make_ssl_client_by_address_and_port, make_ssl_client_by_port,
|
||||||
|
make_client_by_address_and_port, make_client_by_port,
|
||||||
|
make_empty
|
||||||
|
|
||||||
create {HTTPD_STREAM_SOCKET}
|
create {HTTPD_STREAM_SOCKET}
|
||||||
make
|
make
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
make_ssl_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt: STRING; a_key: STRING)
|
make_ssl_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt_fn, a_key_fn: detachable READABLE_STRING_GENERAL)
|
||||||
local
|
local
|
||||||
l_socket: SSL_TCP_STREAM_SOCKET
|
l_socket: SSL_TCP_STREAM_SOCKET
|
||||||
do
|
do
|
||||||
create l_socket.make_server_by_address_and_port (an_address, a_port)
|
create l_socket.make_server_by_address_and_port (an_address, a_port)
|
||||||
l_socket.set_tls_protocol (a_ssl_protocol)
|
l_socket.set_tls_protocol (a_ssl_protocol)
|
||||||
socket := l_socket
|
socket := l_socket
|
||||||
set_certificates (a_crt, a_key)
|
set_certificates (a_crt_fn, a_key_fn)
|
||||||
end
|
end
|
||||||
|
|
||||||
make_ssl_server_by_port (a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt: STRING; a_key: STRING)
|
make_ssl_server_by_port (a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt_fn, a_key_fn: detachable READABLE_STRING_GENERAL)
|
||||||
local
|
local
|
||||||
l_socket: SSL_TCP_STREAM_SOCKET
|
l_socket: SSL_TCP_STREAM_SOCKET
|
||||||
do
|
do
|
||||||
create l_socket.make_server_by_port (a_port)
|
create l_socket.make_server_by_port (a_port)
|
||||||
l_socket.set_tls_protocol (a_ssl_protocol)
|
l_socket.set_tls_protocol (a_ssl_protocol)
|
||||||
socket := l_socket
|
socket := l_socket
|
||||||
set_certificates (a_crt, a_key)
|
set_certificates (a_crt_fn, a_key_fn)
|
||||||
|
end
|
||||||
|
|
||||||
|
make_ssl_client_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt_fn, a_key_fn: detachable READABLE_STRING_GENERAL)
|
||||||
|
local
|
||||||
|
l_socket: SSL_TCP_STREAM_SOCKET
|
||||||
|
do
|
||||||
|
create l_socket.make_client_by_address_and_port (an_address, a_port)
|
||||||
|
l_socket.set_tls_protocol (a_ssl_protocol)
|
||||||
|
socket := l_socket
|
||||||
|
set_certificates (a_crt_fn, a_key_fn)
|
||||||
|
end
|
||||||
|
|
||||||
|
make_ssl_client_by_port (a_peer_port: INTEGER; a_peer_host: STRING; a_ssl_protocol: NATURAL; a_crt_fn, a_key_fn: detachable READABLE_STRING_GENERAL)
|
||||||
|
local
|
||||||
|
l_socket: SSL_TCP_STREAM_SOCKET
|
||||||
|
do
|
||||||
|
create l_socket.make_client_by_port (a_peer_port, a_peer_host)
|
||||||
|
l_socket.set_tls_protocol (a_ssl_protocol)
|
||||||
|
socket := l_socket
|
||||||
|
set_certificates (a_crt_fn, a_key_fn)
|
||||||
|
end
|
||||||
|
|
||||||
|
make_empty
|
||||||
|
-- <Precursor>.
|
||||||
|
do
|
||||||
|
create {SSL_TCP_STREAM_SOCKET} socket.make_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Output
|
feature -- Output
|
||||||
@@ -114,15 +144,15 @@ feature -- Status Report
|
|||||||
|
|
||||||
feature {HTTPD_STREAM_SOCKET} -- Implementation
|
feature {HTTPD_STREAM_SOCKET} -- Implementation
|
||||||
|
|
||||||
set_certificates (a_crt: STRING; a_key: STRING)
|
set_certificates (a_crt_filename, a_key_filename: detachable READABLE_STRING_GENERAL)
|
||||||
local
|
|
||||||
a_file_name: FILE_NAME
|
|
||||||
do
|
do
|
||||||
if attached {SSL_NETWORK_STREAM_SOCKET} socket as l_socket then
|
if attached {SSL_NETWORK_STREAM_SOCKET} socket as l_socket then
|
||||||
create a_file_name.make_from_string (a_crt)
|
if a_crt_filename /= Void then
|
||||||
l_socket.set_certificate_file_name (a_file_name)
|
l_socket.set_certificate_file_name (a_crt_filename)
|
||||||
create a_file_name.make_from_string (a_key)
|
end
|
||||||
l_socket.set_key_file_name (a_file_name)
|
if a_key_filename /= Void then
|
||||||
|
l_socket.set_key_file_name (a_key_filename)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@ inherit
|
|||||||
|
|
||||||
create
|
create
|
||||||
make_server_by_address_and_port, make_server_by_port,
|
make_server_by_address_and_port, make_server_by_port,
|
||||||
|
make_client_by_address_and_port, make_client_by_port,
|
||||||
make_empty
|
make_empty
|
||||||
|
|
||||||
create {SSL_NETWORK_STREAM_SOCKET}
|
create {SSL_NETWORK_STREAM_SOCKET}
|
||||||
@@ -12,9 +12,13 @@ inherit
|
|||||||
make
|
make
|
||||||
end
|
end
|
||||||
|
|
||||||
|
TCP_STREAM_SOCKET_EXT
|
||||||
|
|
||||||
create
|
create
|
||||||
make_server_by_address_and_port,
|
make_server_by_address_and_port,
|
||||||
make_server_by_port,
|
make_server_by_port,
|
||||||
|
make_client_by_address_and_port,
|
||||||
|
make_client_by_port,
|
||||||
make_from_separate,
|
make_from_separate,
|
||||||
make_empty
|
make_empty
|
||||||
|
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Until 16.05, the EiffelNet socket interface DOES NOT have recv_timeout and send_timeout.
|
||||||
|
]"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
TCP_STREAM_SOCKET_EXT
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
descriptor: INTEGER
|
||||||
|
-- Socket descriptor of current socket
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Socket Recv and Send timeout.
|
||||||
|
|
||||||
|
-- recv_timeout: INTEGER
|
||||||
|
-- -- Receive timeout in seconds on Current socket.
|
||||||
|
-- do
|
||||||
|
-- Result := c_get_sock_recv_timeout (descriptor, level_sol_socket)
|
||||||
|
-- ensure
|
||||||
|
-- result_not_negative: Result >= 0
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- send_timeout: INTEGER
|
||||||
|
-- -- Send timeout in seconds on Current socket.
|
||||||
|
-- do
|
||||||
|
-- Result := c_get_sock_send_timeout (descriptor, level_sol_socket)
|
||||||
|
-- ensure
|
||||||
|
-- result_not_negative: Result >= 0
|
||||||
|
-- end
|
||||||
|
|
||||||
|
set_recv_timeout (a_timeout_seconds: INTEGER)
|
||||||
|
-- Set the receive timeout in seconds on Current socket.
|
||||||
|
-- if `0' the related operations will never timeout.
|
||||||
|
require
|
||||||
|
positive_timeout: a_timeout_seconds >= 0
|
||||||
|
do
|
||||||
|
c_set_sock_recv_timeout (descriptor, level_sol_socket, a_timeout_seconds)
|
||||||
|
end
|
||||||
|
|
||||||
|
set_send_timeout (a_timeout_seconds: INTEGER)
|
||||||
|
-- Set the send timeout in milliseconds on Current socket.
|
||||||
|
-- if `0' the related operations will never timeout.
|
||||||
|
require
|
||||||
|
positive_timeout: a_timeout_seconds >= 0
|
||||||
|
do
|
||||||
|
c_set_sock_send_timeout (descriptor, level_sol_socket, a_timeout_seconds)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Externals
|
||||||
|
|
||||||
|
level_sol_socket: INTEGER
|
||||||
|
-- SOL_SOCKET level of options
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
-- set_so_rcvtimeo (a_timeout_seconds: INTEGER)
|
||||||
|
-- -- Set the receive timeout in seconds on Current socket.
|
||||||
|
-- -- if `0' the related operations will never timeout.
|
||||||
|
-- require
|
||||||
|
-- positive_timeout: a_timeout_seconds >= 0
|
||||||
|
-- do
|
||||||
|
-- c_set_sock_recv_timeout (descriptor, level_sol_socket, a_timeout_seconds)
|
||||||
|
-- end
|
||||||
|
|
||||||
|
c_set_sock_recv_timeout (a_fd, a_level: INTEGER; a_timeout_seconds: INTEGER)
|
||||||
|
-- C routine to set socket option `SO_RCVTIMEO' with `a_timeout_seconds' seconds.
|
||||||
|
external
|
||||||
|
"C inline"
|
||||||
|
alias
|
||||||
|
"[
|
||||||
|
#ifdef EIF_WINDOWS
|
||||||
|
int arg = (int) 1000 * $a_timeout_seconds; /* Timeout in milliseconds */
|
||||||
|
setsockopt((SOCKET) $a_fd, (int) $a_level, (int) SO_RCVTIMEO, (char *) &arg, sizeof(arg));
|
||||||
|
#else
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = $a_timeout_seconds; /* Timeout in seconds */
|
||||||
|
|
||||||
|
setsockopt((int) $a_fd, (int) $a_level, (int) SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval));
|
||||||
|
#endif
|
||||||
|
]"
|
||||||
|
end
|
||||||
|
|
||||||
|
c_set_sock_send_timeout (a_fd, a_level: INTEGER; a_timeout_seconds: INTEGER)
|
||||||
|
-- C routine to set socket option `SO_SNDTIMEO' with `a_timeout_seconds' seconds.
|
||||||
|
external
|
||||||
|
"C inline"
|
||||||
|
alias
|
||||||
|
"[
|
||||||
|
#ifdef EIF_WINDOWS
|
||||||
|
int arg = (int) 1000 * $a_timeout_seconds; /* Timeout in milliseconds */
|
||||||
|
setsockopt((SOCKET) $a_fd, (int) $a_level, (int) SO_SNDTIMEO, (char *) &arg, sizeof(arg));
|
||||||
|
#else
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = $a_timeout_seconds; /* Timeout in seconds */
|
||||||
|
|
||||||
|
setsockopt((int) $a_fd, (int) $a_level, (int) SO_SNDTIMEO, (struct timeval *)&tv, sizeof(struct timeval));
|
||||||
|
#endif
|
||||||
|
]"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {HTTPD_SOCKET_FACTORY}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
HTTPD_SOCKET_FACTORY
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
new_client_socket (a_is_secure: BOOLEAN): HTTPD_STREAM_SOCKET
|
||||||
|
do
|
||||||
|
check not_secure: not a_is_secure end
|
||||||
|
create Result.make_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package httpd
|
||||||
|
|
||||||
|
project
|
||||||
|
httpd = "httpd-safe.ecf"
|
||||||
|
httpd = "httpd.ecf"
|
||||||
|
|
||||||
|
note
|
||||||
|
title: HTTP server
|
||||||
|
description: "[
|
||||||
|
Simple HTTP listener and handler, that can be extended easily.
|
||||||
|
]"
|
||||||
|
tags: http,httpd,server,web
|
||||||
|
collection: EWF
|
||||||
|
copyright: 2011-2016, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others
|
||||||
|
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||||
|
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||||
|
link[source]: "Github" https://github.com/EiffelWebFramework/EWF/library/server/httpd
|
||||||
|
link[doc]: "Documentation" http://eiffelwebframework.github.io/EWF/
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {HTTPD_SOCKET_FACTORY}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
HTTPD_SOCKET_FACTORY
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
new_client_socket (a_is_secure: BOOLEAN): HTTPD_STREAM_SOCKET
|
||||||
|
do
|
||||||
|
if a_is_secure then
|
||||||
|
create {HTTPD_STREAM_SSL_SOCKET} Result.make_empty
|
||||||
|
else
|
||||||
|
create Result.make_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
note
|
|
||||||
description: "Configuration for the standalone HTTPd server."
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
deferred class
|
|
||||||
HTTPD_CONFIGURATION_I
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make
|
|
||||||
do
|
|
||||||
http_server_port := 80
|
|
||||||
max_concurrent_connections := 100
|
|
||||||
max_tcp_clients := 100
|
|
||||||
socket_accept_timeout := 1_000
|
|
||||||
socket_connect_timeout := 5_000
|
|
||||||
keep_alive_timeout := 5
|
|
||||||
is_secure := False
|
|
||||||
create ca_crt.make_empty
|
|
||||||
create ca_key.make_empty
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
Server_details: STRING_8
|
|
||||||
-- Detail of the server.
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
http_server_name: detachable READABLE_STRING_8 assign set_http_server_name
|
|
||||||
http_server_port: INTEGER assign set_http_server_port
|
|
||||||
max_tcp_clients: INTEGER assign set_max_tcp_clients
|
|
||||||
max_concurrent_connections: INTEGER assign set_max_concurrent_connections
|
|
||||||
socket_accept_timeout: INTEGER assign set_socket_accept_timeout
|
|
||||||
socket_connect_timeout: INTEGER assign set_socket_connect_timeout
|
|
||||||
force_single_threaded: BOOLEAN assign set_force_single_threaded
|
|
||||||
do
|
|
||||||
Result := (max_concurrent_connections = 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
is_verbose: BOOLEAN assign set_is_verbose
|
|
||||||
-- Display verbose message to the output?
|
|
||||||
|
|
||||||
keep_alive_timeout: INTEGER assign set_keep_alive_timeout
|
|
||||||
-- Persistent connection timeout
|
|
||||||
-- Timeout unit in Seconds.
|
|
||||||
|
|
||||||
has_ssl_support: BOOLEAN
|
|
||||||
-- Has SSL support?
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access: SSL
|
|
||||||
|
|
||||||
is_secure: BOOLEAN
|
|
||||||
-- Is SSL/TLS session?.
|
|
||||||
|
|
||||||
ca_crt: STRING
|
|
||||||
-- the signed certificate.
|
|
||||||
|
|
||||||
ca_key: STRING
|
|
||||||
-- private key to the certificate.
|
|
||||||
|
|
||||||
ssl_protocol: NATURAL
|
|
||||||
-- By default protocol is tls 1.2.
|
|
||||||
|
|
||||||
feature -- Element change
|
|
||||||
|
|
||||||
set_http_server_name (v: detachable separate READABLE_STRING_8)
|
|
||||||
do
|
|
||||||
if v = Void then
|
|
||||||
unset_http_server_name
|
|
||||||
else
|
|
||||||
create {IMMUTABLE_STRING_8} http_server_name.make_from_separate (v)
|
|
||||||
end
|
|
||||||
--| Missing postcondition.
|
|
||||||
end
|
|
||||||
|
|
||||||
unset_http_server_name
|
|
||||||
-- Unset `http_server_name' value.
|
|
||||||
do
|
|
||||||
http_server_name := Void
|
|
||||||
ensure
|
|
||||||
unset_http_server_name: http_server_name = Void
|
|
||||||
end
|
|
||||||
|
|
||||||
set_http_server_port (v: like http_server_port)
|
|
||||||
-- Set `http_server_port' with `v'.
|
|
||||||
do
|
|
||||||
http_server_port := v
|
|
||||||
ensure
|
|
||||||
http_server_port_set: http_server_port = v
|
|
||||||
end
|
|
||||||
|
|
||||||
set_max_tcp_clients (v: like max_tcp_clients)
|
|
||||||
-- Set `max_tcp_clients' with `v'.
|
|
||||||
do
|
|
||||||
max_tcp_clients := v
|
|
||||||
ensure
|
|
||||||
max_tcp_clients_set: max_tcp_clients = v
|
|
||||||
end
|
|
||||||
|
|
||||||
set_max_concurrent_connections (v: like max_concurrent_connections)
|
|
||||||
-- Set `max_concurrent_connections' with `v'.
|
|
||||||
do
|
|
||||||
max_concurrent_connections := v
|
|
||||||
ensure
|
|
||||||
max_concurrent_connections_set : max_concurrent_connections = v
|
|
||||||
end
|
|
||||||
|
|
||||||
set_socket_accept_timeout (v: like socket_accept_timeout)
|
|
||||||
-- Set `socket_accept_timeout' with `v'
|
|
||||||
do
|
|
||||||
socket_accept_timeout := v
|
|
||||||
ensure
|
|
||||||
socket_accept_timeout_set: socket_accept_timeout = v
|
|
||||||
end
|
|
||||||
|
|
||||||
set_socket_connect_timeout (v: like socket_connect_timeout)
|
|
||||||
-- Set `socket_connect_timeout' with `v'
|
|
||||||
do
|
|
||||||
socket_connect_timeout := v
|
|
||||||
ensure
|
|
||||||
socket_connect_timeout_set: socket_connect_timeout = v
|
|
||||||
end
|
|
||||||
|
|
||||||
set_force_single_threaded (v: like force_single_threaded)
|
|
||||||
do
|
|
||||||
if v then
|
|
||||||
set_max_concurrent_connections (0)
|
|
||||||
end
|
|
||||||
--|Missing postcondition
|
|
||||||
--| force_single_thread_set: v implies max_concurrent_connections = 0
|
|
||||||
--| not_single_thread: not v implies max_concurrent_connections > 0
|
|
||||||
end
|
|
||||||
|
|
||||||
set_is_verbose (b: BOOLEAN)
|
|
||||||
-- Set `is_verbose' to `b'
|
|
||||||
do
|
|
||||||
is_verbose := b
|
|
||||||
ensure
|
|
||||||
is_verbose_set: is_verbose = b
|
|
||||||
end
|
|
||||||
|
|
||||||
set_keep_alive_timeout (a_seconds: like keep_alive_timeout)
|
|
||||||
-- Set `keep_alive_timeout' with `a_seconds'
|
|
||||||
do
|
|
||||||
keep_alive_timeout := a_seconds
|
|
||||||
ensure
|
|
||||||
keep_alive_timeout_set: keep_alive_timeout = a_seconds
|
|
||||||
end
|
|
||||||
|
|
||||||
mark_secure
|
|
||||||
-- Set is_secure in True
|
|
||||||
do
|
|
||||||
if has_ssl_support then
|
|
||||||
is_secure := True
|
|
||||||
if http_server_port = 80 then
|
|
||||||
set_http_server_port (443)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
is_secure := False
|
|
||||||
end
|
|
||||||
ensure
|
|
||||||
is_secure_set: has_ssl_support implies is_secure
|
|
||||||
-- http_server_port_set: has_ssl_support implies http_server_port = 443
|
|
||||||
is_not_secure: not has_ssl_support implies not is_secure
|
|
||||||
-- default_port: not has_ssl_support implies http_server_port = 80
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Element change
|
|
||||||
|
|
||||||
set_ca_crt (a_value: STRING)
|
|
||||||
-- Set `ca_crt' with `a_value'
|
|
||||||
do
|
|
||||||
ca_crt := a_value
|
|
||||||
ensure
|
|
||||||
ca_crt_set: ca_crt = a_value
|
|
||||||
end
|
|
||||||
|
|
||||||
set_ca_key (a_value: STRING)
|
|
||||||
-- Set `ca_key' with `a_value'
|
|
||||||
do
|
|
||||||
ca_key := a_value
|
|
||||||
ensure
|
|
||||||
ca_key_set: ca_key = a_value
|
|
||||||
end
|
|
||||||
|
|
||||||
set_ssl_protocol (a_version: NATURAL)
|
|
||||||
-- Set `ssl_protocol' with `a_version'
|
|
||||||
do
|
|
||||||
ssl_protocol := a_version
|
|
||||||
ensure
|
|
||||||
ssl_protocol_set: ssl_protocol = a_version
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- SSL Helpers
|
|
||||||
|
|
||||||
set_ssl_protocol_to_ssl_2_or_3
|
|
||||||
-- Set `ssl_protocol' with `Ssl_23'.
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
set_ssl_protocol_to_tls_1_0
|
|
||||||
-- Set `ssl_protocol' with `Tls_1_0'.
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
set_ssl_protocol_to_tls_1_1
|
|
||||||
-- Set `ssl_protocol' with `Tls_1_1'.
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
set_ssl_protocol_to_tls_1_2
|
|
||||||
-- Set `ssl_protocol' with `Tls_1_2'.
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
set_ssl_protocol_to_dtls_1_0
|
|
||||||
-- Set `ssl_protocol' with `Dtls_1_0'.
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
note
|
|
||||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
|
||||||
source: "[
|
|
||||||
Eiffel Software
|
|
||||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
|
||||||
Telephone 805-685-1006, Fax 805-685-6869
|
|
||||||
Website http://www.eiffel.com
|
|
||||||
Customer support http://support.eiffel.com
|
|
||||||
]"
|
|
||||||
end
|
|
||||||
@@ -24,13 +24,10 @@ create
|
|||||||
|
|
||||||
feature {NONE} -- Initialization
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
make_with_connector (conn: like connector)
|
make_with_connector (a_request_settings: HTTPD_REQUEST_SETTINGS; conn: like connector)
|
||||||
do
|
do
|
||||||
make
|
make (a_request_settings)
|
||||||
connector := conn
|
connector := conn
|
||||||
-- if conn /= Void then
|
|
||||||
-- set_is_verbose (is_connector_verbose (conn))
|
|
||||||
-- end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
@@ -56,11 +53,6 @@ feature -- SCOOP helpers
|
|||||||
Result := conn.base
|
Result := conn.base
|
||||||
end
|
end
|
||||||
|
|
||||||
is_connector_verbose (conn: separate WGI_STANDALONE_CONNECTOR [G]): BOOLEAN
|
|
||||||
do
|
|
||||||
Result := conn.is_verbose
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Request processing
|
feature -- Request processing
|
||||||
|
|
||||||
process_request (a_socket: HTTPD_STREAM_SOCKET)
|
process_request (a_socket: HTTPD_STREAM_SOCKET)
|
||||||
@@ -87,7 +79,7 @@ feature -- Request processing
|
|||||||
else
|
else
|
||||||
l_output.set_http_version (version)
|
l_output.set_http_version (version)
|
||||||
end
|
end
|
||||||
res.set_is_persistent_connection_supported ({HTTPD_SERVER}.is_persistent_connection_supported)
|
res.set_is_persistent_connection_supported (is_persistent_connection_supported and is_next_persistent_connection_supported)
|
||||||
res.set_is_persistent_connection_requested (is_persistent_connection_requested)
|
res.set_is_persistent_connection_requested (is_persistent_connection_requested)
|
||||||
|
|
||||||
req.set_meta_string_variable ("RAW_HEADER_DATA", request_header)
|
req.set_meta_string_variable ("RAW_HEADER_DATA", request_header)
|
||||||
@@ -238,6 +230,9 @@ feature -- Request processing
|
|||||||
set_environment_variable (l_server_port, "SERVER_PORT", Result)
|
set_environment_variable (l_server_port, "SERVER_PORT", Result)
|
||||||
set_environment_variable (version, "SERVER_PROTOCOL", Result)
|
set_environment_variable (version, "SERVER_PROTOCOL", Result)
|
||||||
set_environment_variable ({HTTPD_CONFIGURATION}.Server_details, "SERVER_SOFTWARE", Result)
|
set_environment_variable ({HTTPD_CONFIGURATION}.Server_details, "SERVER_SOFTWARE", Result)
|
||||||
|
if is_secure then
|
||||||
|
set_environment_variable ("on", "HTTPS", Result)
|
||||||
|
end
|
||||||
|
|
||||||
--| Apply `base' value
|
--| Apply `base' value
|
||||||
l_base := base
|
l_base := base
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
note
|
note
|
||||||
description: "Implementation of WGI request handler factory for WGI_STANDALOE_CONNECTOR."
|
description: "Implementation of WGI request handler factory for WGI_STANDALONE_CONNECTOR."
|
||||||
date: "$Date$"
|
date: "$Date$"
|
||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
|
|
||||||
@@ -14,19 +14,23 @@ feature -- Access
|
|||||||
connector: detachable separate WGI_STANDALONE_CONNECTOR [G]
|
connector: detachable separate WGI_STANDALONE_CONNECTOR [G]
|
||||||
-- httpd solution.
|
-- httpd solution.
|
||||||
|
|
||||||
|
request_settings: HTTPD_REQUEST_SETTINGS
|
||||||
|
-- Settings specific to request handling.
|
||||||
|
|
||||||
feature -- Element change
|
feature -- Element change
|
||||||
|
|
||||||
set_connector (conn: like connector)
|
update_with (conn: like connector; a_conf: separate HTTPD_CONFIGURATION)
|
||||||
-- Set `connector' with `conn'.
|
-- Set `connector' with `conn'.
|
||||||
do
|
do
|
||||||
connector := conn
|
connector := conn
|
||||||
|
request_settings := a_conf.request_settings
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Factory
|
feature -- Factory
|
||||||
|
|
||||||
new_handler: separate WGI_HTTPD_REQUEST_HANDLER [G]
|
new_handler: separate WGI_HTTPD_REQUEST_HANDLER [G]
|
||||||
do
|
do
|
||||||
create Result.make_with_connector (connector)
|
create Result.make_with_connector (request_settings, connector)
|
||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
note
|
note
|
||||||
description: "[
|
description: "[
|
||||||
Standalone Web Server connector
|
Standalone Web Server connector.
|
||||||
]"
|
]"
|
||||||
date: "$Date$"
|
date: "$Date: 2016-08-06 13:34:52 +0200 (sam., 06 août 2016) $"
|
||||||
revision: "$Revision$"
|
revision: "$Revision: 99106 $"
|
||||||
|
|
||||||
class
|
class
|
||||||
WGI_STANDALONE_CONNECTOR [G -> WGI_EXECUTION create make end]
|
WGI_STANDALONE_CONNECTOR [G -> WGI_EXECUTION create make end]
|
||||||
@@ -20,18 +20,18 @@ feature {NONE} -- Initialization
|
|||||||
make
|
make
|
||||||
-- Create current standalone connector.
|
-- Create current standalone connector.
|
||||||
local
|
local
|
||||||
fac: separate WGI_HTTPD_REQUEST_HANDLER_FACTORY [G]
|
fac: like request_handler_factory
|
||||||
do
|
do
|
||||||
-- Callbacks
|
-- Callbacks
|
||||||
create on_launched_actions
|
create on_launched_actions
|
||||||
|
|
||||||
-- Server
|
-- Server
|
||||||
create fac
|
create <NONE> fac
|
||||||
|
request_handler_factory := fac
|
||||||
create server.make (fac)
|
create server.make (fac)
|
||||||
create observer
|
create <NONE> observer
|
||||||
configuration := server_configuration (server)
|
configuration := server_configuration (server)
|
||||||
controller := server_controller (server)
|
controller := server_controller (server)
|
||||||
set_factory_connector (Current, fac)
|
|
||||||
initialize_server (server)
|
initialize_server (server)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -51,9 +51,9 @@ feature {NONE} -- Separate helper
|
|||||||
a_server.set_observer (observer)
|
a_server.set_observer (observer)
|
||||||
end
|
end
|
||||||
|
|
||||||
set_factory_connector (conn: detachable separate WGI_STANDALONE_CONNECTOR [G]; fac: separate WGI_HTTPD_REQUEST_HANDLER_FACTORY [G])
|
update_factory (conn: detachable separate WGI_STANDALONE_CONNECTOR [G]; fac: separate WGI_HTTPD_REQUEST_HANDLER_FACTORY [G]; a_conf: like configuration)
|
||||||
do
|
do
|
||||||
fac.set_connector (conn)
|
fac.update_with (conn, a_conf)
|
||||||
end
|
end
|
||||||
|
|
||||||
server_configuration (a_server: like server): like configuration
|
server_configuration (a_server: like server): like configuration
|
||||||
@@ -63,17 +63,26 @@ feature {NONE} -- Separate helper
|
|||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
name: STRING_8 = "httpd"
|
name: STRING_8
|
||||||
-- Name of Current connector
|
-- Name of Current connector
|
||||||
|
once
|
||||||
|
Result := "httpd"
|
||||||
|
end
|
||||||
|
|
||||||
version: STRING_8 = "0.1"
|
version: STRING_8
|
||||||
-- Version of Current connector
|
-- Version of Current connector
|
||||||
|
once
|
||||||
|
Result := "1.0"
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
server: separate HTTPD_SERVER
|
server: separate HTTPD_SERVER
|
||||||
-- HTTPd server object.
|
-- HTTPd server object.
|
||||||
|
|
||||||
|
request_handler_factory: separate WGI_HTTPD_REQUEST_HANDLER_FACTORY [G]
|
||||||
|
-- Factory for request handlers.
|
||||||
|
|
||||||
controller: separate HTTPD_CONTROLLER
|
controller: separate HTTPD_CONTROLLER
|
||||||
-- Controller used to shutdown server.
|
-- Controller used to shutdown server.
|
||||||
|
|
||||||
@@ -97,9 +106,6 @@ feature -- Status report
|
|||||||
-- Listening port.
|
-- Listening port.
|
||||||
--| 0: not launched
|
--| 0: not launched
|
||||||
|
|
||||||
is_verbose: BOOLEAN
|
|
||||||
-- Is verbose?
|
|
||||||
|
|
||||||
feature -- Callbacks
|
feature -- Callbacks
|
||||||
|
|
||||||
on_launched_actions: ACTION_SEQUENCE [TUPLE [WGI_STANDALONE_CONNECTOR [WGI_EXECUTION]]]
|
on_launched_actions: ACTION_SEQUENCE [TUPLE [WGI_STANDALONE_CONNECTOR [WGI_EXECUTION]]]
|
||||||
@@ -149,6 +155,12 @@ feature -- Element change
|
|||||||
set_is_verbose_on_configuration (b, configuration)
|
set_is_verbose_on_configuration (b, configuration)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
set_is_secure (b: BOOLEAN)
|
||||||
|
-- Set is_secure connection mode.
|
||||||
|
-- i.e: using SSL.
|
||||||
|
do
|
||||||
|
set_is_secure_on_configuration (b, configuration)
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Server
|
feature -- Server
|
||||||
|
|
||||||
@@ -190,18 +202,22 @@ feature {NONE} -- Implementation
|
|||||||
Result := a_server.controller
|
Result := a_server.controller
|
||||||
end
|
end
|
||||||
|
|
||||||
configure_server (a_configuration: like configuration)
|
apply_configuration (a_configuration: like configuration)
|
||||||
|
local
|
||||||
|
v: BOOLEAN
|
||||||
do
|
do
|
||||||
if a_configuration.is_verbose then
|
v := a_configuration.is_verbose
|
||||||
if attached base as l_base then
|
if v then
|
||||||
|
if attached base as l_base and then not l_base.is_whitespace then
|
||||||
io.error.put_string ("Base=" + l_base + "%N")
|
io.error.put_string ("Base=" + l_base + "%N")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
update_factory (Current, request_handler_factory, a_configuration)
|
||||||
end
|
end
|
||||||
|
|
||||||
launch_server (a_server: like server)
|
launch_server (a_server: like server)
|
||||||
do
|
do
|
||||||
configure_server (a_server.configuration)
|
apply_configuration (a_server.configuration)
|
||||||
a_server.launch
|
a_server.launch
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -229,13 +245,17 @@ feature {NONE} -- Implementation: element change
|
|||||||
|
|
||||||
set_is_verbose_on_configuration (b: BOOLEAN; cfg: like configuration)
|
set_is_verbose_on_configuration (b: BOOLEAN; cfg: like configuration)
|
||||||
do
|
do
|
||||||
is_verbose := b
|
|
||||||
cfg.set_is_verbose (b)
|
cfg.set_is_verbose (b)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
set_is_secure_on_configuration (b: BOOLEAN; cfg: like configuration)
|
||||||
|
do
|
||||||
|
cfg.set_is_secure (b)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Interface to access protected feature from {WGI_STANDALONE_CONNECTOR}.
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
WGI_STANDALONE_CONNECTOR_EXPORTER
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Constants value related to Standalone connector,
|
||||||
|
and indirectly to `httpd' component.
|
||||||
|
]"
|
||||||
|
author: "$Author$"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
WGI_STANDALONE_CONSTANTS
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ANY
|
||||||
|
|
||||||
|
HTTPD_CONSTANTS
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
note
|
||||||
|
description: "Export HTTPD_LOGGER_CONSTANTS to Standlone connector interfaces."
|
||||||
|
|
||||||
|
class
|
||||||
|
WGI_STANDALONE_HTTPD_LOGGER_CONSTANTS
|
||||||
|
|
||||||
|
inherit
|
||||||
|
HTTPD_LOGGER_CONSTANTS
|
||||||
|
|
||||||
|
end
|
||||||
@@ -24,7 +24,7 @@ feature {NONE} -- Initialization
|
|||||||
set_source (a_source)
|
set_source (a_source)
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {WGI_STANDALONE_CONNECTOR, WGI_SERVICE} -- Nino
|
feature {WGI_STANDALONE_CONNECTOR, WGI_SERVICE, WGI_STANDALONE_CONNECTOR_EXPORTER} -- Standalone
|
||||||
|
|
||||||
set_source (i: like source)
|
set_source (i: like source)
|
||||||
do
|
do
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ feature -- Header output operation
|
|||||||
l_connection := s.substring (i + 12, j - 1)
|
l_connection := s.substring (i + 12, j - 1)
|
||||||
l_connection.adjust
|
l_connection.adjust
|
||||||
if
|
if
|
||||||
not is_http_version_1_0 and
|
|
||||||
not l_connection.is_case_insensitive_equal_general ("close")
|
not l_connection.is_case_insensitive_equal_general ("close")
|
||||||
then
|
then
|
||||||
s.replace_substring ("Connection: close", i + 1, j - 1)
|
s.replace_substring ("Connection: close", i + 1, j - 1)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<library name="encoder" location="..\..\..\..\text\encoder\encoder-safe.ecf"/>
|
<library name="encoder" location="..\..\..\..\text\encoder\encoder-safe.ecf"/>
|
||||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||||
<library name="http" location="..\..\..\..\network\protocol\http\http-safe.ecf"/>
|
<library name="http" location="..\..\..\..\network\protocol\http\http-safe.ecf"/>
|
||||||
<library name="httpd" location="src\httpd\httpd-safe.ecf" readonly="false"/>
|
<library name="httpd" location="lib\httpd\httpd-safe.ecf" readonly="false"/>
|
||||||
<cluster name="src" location=".\src\">
|
<cluster name="src" location=".\src\">
|
||||||
<cluster name="implementation" location="$|implementation\" hidden="true"/>
|
<cluster name="implementation" location="$|implementation\" hidden="true"/>
|
||||||
</cluster>
|
</cluster>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<library name="encoder" location="..\..\..\..\text\encoder\encoder.ecf"/>
|
<library name="encoder" location="..\..\..\..\text\encoder\encoder.ecf"/>
|
||||||
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
|
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
|
||||||
<library name="http" location="..\..\..\..\network\protocol\http\http.ecf"/>
|
<library name="http" location="..\..\..\..\network\protocol\http\http.ecf"/>
|
||||||
<library name="httpd" location="src\httpd\httpd.ecf" readonly="false"/>
|
<library name="httpd" location="lib\httpd\httpd.ecf" readonly="false"/>
|
||||||
<cluster name="src" location=".\src\">
|
<cluster name="src" location=".\src\">
|
||||||
<cluster name="implementation" location="$|implementation\" hidden="true"/>
|
<cluster name="implementation" location="$|implementation\" hidden="true"/>
|
||||||
</cluster>
|
</cluster>
|
||||||
|
|||||||
@@ -10,12 +10,11 @@
|
|||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
<library name="connector_standalone" location="standalone-safe.ecf" readonly="false"/>
|
<library name="connector_standalone" location="standalone-safe.ecf" readonly="false"/>
|
||||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||||
<library name="httpd_edit" location="src\httpd\httpd-safe.ecf" readonly="false">
|
<library name="httpd_edit" location="lib\httpd\httpd-safe.ecf" readonly="false">
|
||||||
<option debug="true">
|
<option debug="true">
|
||||||
<debug name="dbglog" enabled="true"/>
|
<debug name="dbglog" enabled="true"/>
|
||||||
</option>
|
</option>
|
||||||
</library>
|
</library>
|
||||||
<library name="net_ssl_edit" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl-safe.ecf" readonly="false"/>
|
|
||||||
<library name="wsf" location="..\..\..\wsf\wsf-safe.ecf" readonly="false"/>
|
<library name="wsf" location="..\..\..\wsf\wsf-safe.ecf" readonly="false"/>
|
||||||
<cluster name="tests" location="tests\" recursive="true"/>
|
<cluster name="tests" location="tests\" recursive="true"/>
|
||||||
</target>
|
</target>
|
||||||
|
|||||||
@@ -3,21 +3,28 @@ package ewsgi
|
|||||||
project
|
project
|
||||||
ewsgi = "ewsgi-safe.ecf"
|
ewsgi = "ewsgi-safe.ecf"
|
||||||
ewsgi = "ewsgi.ecf"
|
ewsgi = "ewsgi.ecf"
|
||||||
ewsgi_spec = "ewsgi_spec-safe.ecf"
|
|
||||||
ewsgi_spec = "ewsgi_spec.ecf"
|
|
||||||
connector_cgi = "connectors/cgi/cgi-safe.ecf"
|
connector_cgi = "connectors/cgi/cgi-safe.ecf"
|
||||||
connector_cgi = "connectors/cgi/cgi.ecf"
|
connector_cgi = "connectors/cgi/cgi.ecf"
|
||||||
connector_libfcgi = "connectors/libfcgi/libfcgi-safe.ecf"
|
connector_libfcgi = "connectors/libfcgi/libfcgi-safe.ecf"
|
||||||
connector_libfcgi = "connectors/libfcgi/libfcgi.ecf"
|
connector_libfcgi = "connectors/libfcgi/libfcgi.ecf"
|
||||||
connector_nino = "connectors/nino/nino-safe.ecf"
|
|
||||||
connector_nino = "connectors/nino/nino.ecf"
|
|
||||||
connector_null = "connectors/null/null-safe.ecf"
|
connector_null = "connectors/null/null-safe.ecf"
|
||||||
connector_null = "connectors/null/null.ecf"
|
connector_null = "connectors/null/null.ecf"
|
||||||
|
connector_standalone = "connectors/standalone/standalone-safe.ecf"
|
||||||
|
connector_standalone = "connectors/standalone/standalone.ecf"
|
||||||
|
httpd = "connectors/standalone/src/httpd/httpd-safe.ecf"
|
||||||
|
httpd = "connectors/standalone/src/httpd/httpd.ecf"
|
||||||
|
|
||||||
note
|
note
|
||||||
title: EWSGI
|
title: EWSGI
|
||||||
description: EWSGI specification, and a few connectors.
|
description: "[
|
||||||
tags: web, httpd, ewf
|
Eiffel Web Server Gateway Interface (EWSGI) specification, and a few connectors.
|
||||||
license: Eiffel Forum v2
|
]"
|
||||||
|
collection: EWF
|
||||||
|
tags: ewsgi,cgi,web,httpd,ewf
|
||||||
|
copyright: 2011-2016, Jocelyn Fiat, Eiffel Software and others
|
||||||
|
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||||
|
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||||
|
link[source]: "github" https://github.com/EiffelWebFramework/EWF/tree/master/library/server/ewsgi
|
||||||
|
link[doc]: "Documentation" https://github.com/EiffelWebFramework/EWF/tree/master/library/server/ewsgi/doc
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user