Compare commits

...

40 Commits

Author SHA1 Message Date
40fb3893af Include wsf_proxy to the installation process. 2016-09-27 16:18:06 +02:00
21407f8dcf Fixed SSL support on the httpd component, and also on the EiffelWeb standalone connector.
- the standalone connector support for SSL, is using certicate files for now (no in-memory support).
  - to enable ssl support, set ecf variable `httpd_ssl_enabled=true`.
  - added the `simple_ssl` example to demonstrate how to have standalone ssl server.
    (be careful when using EiffelNet SSL and the http_client library, disable the libcurl
      via ecf variable `libcurl_http_client_disabled=true` )

Added support for recv timeout to the EiffelWeb standalone connector.
  - made EiffelWeb compilable with 16.05 and upcoming 16.11.
    Done via ecfs condition on version to accept EiffelNet with recv_timeout (from 16.11), and without (until 16.05).
  - adding recv timeout prevents server to hang for ever if a client wait too long to send data.

Updated various comments.
2016-09-27 16:11:47 +02:00
356eb143ea Fixed the non void-safe ecf for wsf_proxy. 2016-09-26 17:42:49 +02:00
df551d4a4f Use latest API from http_client using DEFAULT_HTTP_CLIENT,
that could use libcurl or EiffelNet depending on the configuration (.ecf).
2016-09-26 13:13:57 +02:00
f010da04e9 Merge branch 'reverse_proxy' 2016-09-19 22:19:21 +02:00
5029049ef0 Replaced host+port by uri (http://remotemachine:port/path).
Added support for SSL (https).
2016-08-08 12:30:28 +02:00
80254b2278 When possible keep ecf location relative within the same EiffelWeb directory structure. 2016-08-06 10:07:42 +02:00
210fae5000 First step towards SSL support. 2016-08-06 10:04:45 +02:00
9cc9b95190 Added a simple reverse proxy handler.
- For now, it does not support SSL connection on the target yet.
- No external config file support, this is all about coding.
2016-08-05 11:38:35 +02:00
8b172b5d33 Revisited WSF_REQUEST.read_input_data* functions:
- read_input_data_into_file now accepts a IO_MEDIUM argument instead of just FILE.
- cleaned the implementation, and make sure that eventual `raw_input_data` is containing only the raw input data.
2016-08-05 11:32:14 +02:00
cc2d7dbb1c Ignore empty header line. 2016-08-05 11:28:59 +02:00
c88394b9fd Added support for category in ATOM format (input and output). 2016-06-24 13:03:09 +02:00
4283662f43 Removed unwanted .ecf file. 2016-06-22 10:55:41 +02:00
1b951376f9 Added more application logic for the example. 2016-06-22 10:52:36 +02:00
193cc3cbde Renamed WGI_STANDALONE_CONNECTOR_ACCESS as WGI_STANDALONE_CONNECTOR_EXPORTER.
Isolate the websocket implementation in descendant of {WEB_SOCKET_EVENT_I}.
Added very simple echo websocket example.
+ code cleaning.
2016-06-22 10:46:15 +02:00
b49e841ac7 Added WSF standalone_websocket connector, that provides websocket on top of standalone connector. 2016-06-21 23:37:48 +02:00
8ba74e1c90 Log when a persistent connection is reused.
Use anchor type on `{WGI_STANDALONE_CONNECTOR}.configuration` and `{WSF_STANDALONE_SERVICE_LAUNCHER}.connector`.
Add access to the socket of standalone input stream from `{WSF_STANDALONE_CONNECTOR_ACCESS}`.
Removed a useless redefination in `WSF_EXECUTION`.
2016-06-21 23:36:22 +02:00
0cecb9594c Fixed signature of {HTTPD_CONFIGURATION_I}.set_ca_key . 2016-06-16 10:37:26 +02:00
e384a6d6ed Make it easier to reuse the http network classes.
This is to make it easier for websocket solution to reuse httpd implementation.
2016-06-16 10:23:30 +02:00
71a5c086a5 Moved httpd from src to lib, under standalone connector. 2016-06-15 18:04:00 +02:00
dfa60bf8f5 Prepared httpd_stream to be useable for client too.
Fixed obsolete tests/dev compilation (mainly to avoid wrong failure reports).
added package.iron files.
2016-06-15 17:56:22 +02:00
113aa69efc Added advanced settings for standalone connector
- max_concurrent_connections=100
- keep_alive_timeout=15
- max_tcp_clients=100
- socket_timeout=300
- max_keep_alive_requests=300
And then can be set via the options as well, and via .ini file.
Also improved the verbose console output system.
2016-06-15 09:19:23 +02:00
af5fc75743 Using passive regions.
Improve connector options mainly for standalone connector.
Updated "simple" example to return a timestamp.
2016-06-14 16:01:37 +02:00
Jocelyn Fiat
e53c960a89 Added libfcgi target, in addition to standalone target for the upload_image example. 2016-05-31 22:24:26 +02:00
Jocelyn Fiat
63be2c278c Fixed bad usage of {SOCKET}.socket_ok that resulted in bad behavior on linux. 2016-05-31 22:19:52 +02:00
Jocelyn Fiat
f8ba741aa2 Using -lfcgi as external linker flag, rather than /usr/lib/libfcgi.so .
Note on Ubuntu: apt-get install libfcgi-dev
2016-05-31 18:51:15 +02:00
Jocelyn Fiat
fe07af587d Updated link to github pages documentation. 2016-05-31 16:57:06 +02:00
Jocelyn Fiat
a3a9dd1393 Fixed link to image or source code in markdown workbook text. 2016-05-31 16:51:20 +02:00
Jocelyn Fiat
fbb860024d Updated markdown text to conform strictly to kramdown syntax. 2016-05-31 16:39:50 +02:00
Jocelyn Fiat
a14488346f Updated to kramdown markdown syntax (i.e github).
Updated various content and nav links.
2016-05-27 09:51:24 +02:00
Jocelyn Fiat
f74d1b3069 Updated markdown relative links. 2016-05-26 23:11:19 +02:00
Jocelyn Fiat
1ba3528974 Added readme.md in /doc/. And updated workbook readme.md itself. 2016-05-26 10:41:07 +02:00
5890ca6f73 Removed warning about unknown class in export clause. 2016-05-25 22:51:45 +02:00
7f4bf09d84 updated readme.md to link to workbook. 2016-05-25 19:17:38 +02:00
Colin Adams
ad90e7c135 Fix for missing error reporting in WSF_PUT/POST_HELPER 2016-05-20 17:37:47 +02:00
cc3c8af6b4 Updated HTTP_COOKIE implementation
- by default the Cookie does not set max-age and expires, so it defines a Session Cookie.
   (max_age and expires attributes are not included in the response)
 - set_* and unset_* features to define max_age and expire attributes.
 - marked old features as obsolete.
Updated test cases.

Signed-off-by: jvelilla <javier.hector@gmail.com>
2016-05-04 12:26:17 +02:00
b35ec65577 Updated EWF Windows tools to install EWF into EiffelStudio source tree. 2016-02-03 18:03:43 +01:00
4482520a86 Removed useless library declarations. 2016-02-03 15:12:54 +01:00
e9afc9ad17 Updated package.iron files. 2016-02-02 09:57:03 +01:00
55ab6969ee Do not html escape ' with &apos;
reason: the named character reference &apos; (the apostrophe, U+0027) was introduced in XML 1.0 but does not appear in HTML. Authors should therefore use &#39; instead of &apos; to work as expected in HTML 4 user agents.
2016-01-20 17:53:06 +01:00
151 changed files with 5298 additions and 976 deletions

View File

@@ -8,7 +8,8 @@ note
title: Eiffel Nino Web Server
description: Simple HTTPd server written in Eiffel
tags: web, httpd, server
copyright: Javier Velilla, Jocelyn Fiat and Eiffel Software.
license: Eiffel Forum v2
copyright: Javier Velilla, Jocelyn Fiat.
link[license]: http://www.eiffel.com/licensing/forum.txt
end

10
doc/readme.md Normal file
View 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)

View File

@@ -1,3 +1,3 @@
## Diagram: Overview of the server architecture ##
![server_architecture.png](server_architecture.png)
![server_architecture.png](./server_architecture.png)

View File

@@ -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
@@ -11,14 +11,15 @@ Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query Parameter](/doc
- [Source code](#source_2)
<a name="structure"/>
<a name="structure"></a>
## 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.
```eiffel
class
APPLICACTION
APPLICATION
inherit
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.
![Launcher Hierarchy](/doc/workbook/basics/Launcher Hierarchy.png "Launcher Hierarchy")
![Launcher Hierarchy](./Launcher Hierarchy.png "Launcher Hierarchy")
**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.
![Standalone Launcher](/doc/workbook/basics/WSF_SERVICE_LAUNCHER_STANDALONE.png "Standalone Hierarchy")
![Standalone Launcher](./WSF_SERVICE_LAUNCHER_STANDALONE.png "Standalone Hierarchy")
Other connectors:
**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*.
![Execution Hierarchy](/doc/workbook/basics/APPLICATION_EXECUTION.png "Application Execution ")
![Execution Hierarchy](./APPLICATION_EXECUTION.png "Application Execution ")
The WSF_EXECUTION instance, in this case ```APPLICATION_EXECUTION``` is created per request, with two main attributes request: ```WSF_REQUEST``` and response: ```WSF_RESPONSE```.
<a name="text"/>
<a name="text"></a>
## 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.
@@ -142,16 +144,18 @@ end
```
<a name="source_1"></a>
##### Source code
### Source code
The source code is available on Github. You can get it by running the command:
```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```
<a name="html"></a>
## A Service to Generate HTML.
To generate HTML, it's needed
@@ -193,7 +197,10 @@ feature -- Basic operations
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:
```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```
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)

View File

@@ -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
* Compile the ewf application from command line.
* Assuming you have installed Apache Server under C:/home/server/Apache24.
* Assuming you have placed your current project under C:/home/server/Apache24/fcgi-bin.
* Assuming you have setted the Listen to 8888, the defautl value is 80 .
* Assuming you have installed Apache Server under `C:/home/server/Apache24`.
* Assuming you have placed your current project under `C:/home/server/Apache24/fcgi-bin`.
* Assuming you have setted the Listen to `8888`, the defautl value is `80` .
####FCGI module
#### FCGI module
If you don't have the FCGI module installed, you can get it from https://www.apachelounge.com/download/, download the module based on your platform [modules-2.4-win64-VC11.zip](https://www.apachelounge.com/download/VC11/modules/modules-2.4-win64-VC11.zip) or [modules-2.4-win32-VC11.zip](https://www.apachelounge.com/download/VC11/modules/modules-2.4-win32-VC11.zip), uncompress it
and copy the _mod_fcgid.so_ to C:/home/server/Apache24/modules
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 .
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.
####Apache configuration
#### Apache configuration
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
>httpd -t
```
> httpd -t
```
Luanch the server
>httpd
Launch the server
```
> httpd
```
Check the application
>http://localhost:8888/simple
```
> http://localhost:8888/simple
```
Nav: [Workbook](../../../workbook.md) :: [Basic concepts](../../../basics/basics.md)

View File

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

View File

@@ -1,7 +1,9 @@
Nav: [Workbook](../workbook.md)
EWF Deployment
==============
#Apache on Windows#
# Apache on Windows#
1. Apache Install
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)
>Apache Version: Apache 2.4.4
>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.
>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 rewrite_module modules/mod_rewrite.so
####Tip:
#### Tip:
>To check the syntax of your httpd.conf file. From command line run the following
$>httpd - t
@@ -68,7 +70,7 @@ Check that you have the following modules enabled
>.htaccess CGI
http://perishablepress.com/stupid-htaccess-tricks/
####.htaccess
#### .htaccess
Options +ExecCGI +Includes +FollowSymLinks -Indexes
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
####Deploying EWF FCGI
#### Deploying EWF FCGI
>To deploy FCGI you will need to download the mod_fcgi module.
>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.
* 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
#.htaccess FCGI
>http://perishablepress.com/stupid-htaccess-tricks/
# .htaccess FCGI
####.htaccess
```
http://perishablepress.com/stupid-htaccess-tricks/
```
#### .htaccess
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
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)

View File

@@ -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
@@ -14,7 +14,8 @@ Nav: [Workbook](../workbook.md) | [Handling Requests: Header Fields](/doc/workbo
- [Response Header Fields](#header_fields)
<a name="format"/>
<a name="format"></a>
## 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.
@@ -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 dont. For example, responses to HEAD requests should never include a document, and various status codes essentially indicate failure or redirection (and thus either dont 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
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/).
<a name="redirect"/>
<a name="redirect"></a>
## 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```
@@ -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.
<a name="status"/>
<a name="status"></a>
## [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.
@@ -159,7 +163,8 @@ General categories:
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
Basic Service that builds a simple web page to show the most common status codes
```eiffel
@@ -298,7 +303,8 @@ end
<a name="example_2"/>
<a name="example_2"></a>
### 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
redirection works, and we will use a tools to play with the API to show differents responses.
@@ -585,7 +591,8 @@ Connection: close
</html>
```
<a name="header_fields"/>
<a name="header_fields"></a>
## [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.
@@ -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)

View File

@@ -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
@@ -9,9 +9,10 @@ Nav: [Workbook](../workbook.md) | [Generating Responses](/doc/workbook/generatin
- [How to read a cookie](#read_cookie)
- [Examples](#examples)
<a name="cookie"/>
## [Cookie](http://httpwg.github.io/specs/rfc6265.html)
A cookie is a piece of data that can be stored in a browser's cache. If you visit a web site and then revisit it, the cookie data can be used to identify you as a return visitor. Cookies enable state information, such as an online shopping cart, to be remembered. A cookie can be short term, holding data for a single web session, that is, until you close the browser, or a cookie can be longer term, holding data for a week or a year.
<a name="cookie"></a>
## 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.
@@ -30,7 +31,8 @@ Client send cookies to server
<a name="properties"/>
<a name="properties"></a>
### Cookie properties
- Comment: describe the purpose of the cookie. Note that server doesnt 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.
- Version:
<a name="set_get"/>
<a name="set_get"></a>
## 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
@@ -67,7 +70,8 @@ WSF_REQUEST.cookie (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
feature.
<a name="set_cookie"/>
<a name="set_cookie"></a>
### How to set Cookies
Here we have the feature definitions to set cookies
@@ -111,7 +115,8 @@ Example of use:
res.put_string (web_page)
end
```
<a name="read_cookie"/>
<a name="read_cookie"></a>
### How to read Cookies
Reading a particular cookie
@@ -130,7 +135,8 @@ Reading all the cookies
```
<a name="examples"/>
<a name="examples"></a>
### Example
The following EWF service shows a basic use of cookies.
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)

View File

@@ -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)
#Handling Requests: Form/Query Data
Nav: [Workbook](../workbook.md) :: [Basic Concepts](../basics/basics.md) :: [Handling Requests: Header Fields](./headers.md)
# Handling Requests: Form/Query Data
##### Table of Contents
- [Reading Form Data](#read)
- [Query Parameters](#query)
- [Form Parameters](#form)
- [Form Parameters](#form_parameters)
- [Uniform Read](#uniform)
- [Reading Parameters and Values](#reading_pv)
- [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.
* How to populate Eiffel objects from the request data.
<a name="read"/>
<a name="read"></a>
## Reading Form Data
EWF [WSF_REQUEST]() class, provides features to handling this form parsing automatically.
<a name="query"/>
<a name="query"></a>
### Query Parameters
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
-- Query parameter for name `a_name'.
<a name="form"/>
<a name="form_parameters"></a>
### Form Parameters
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.
<a name="uniform"/>
<a name="uniform"></a>
### 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.
@@ -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
<a name="reading_pv">
<a name="reading_pv"></a>
## 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.
@@ -111,7 +114,8 @@ Suppose we have the following HTML5 form using Method POST. This HTML5 form has
</fieldset>
</form>
```
<a name="all_names">
<a name="all_names"></a>
### How to read all parameter names
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
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
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
end
```
<a name="multiple_values">
<a name="multiple_values"></a>
### 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)
@@ -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.
<a name="table_values">
<a name="table_values"></a>
### How to read table values
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
```
<a name="raw_data">
<a name="raw_data"></a>
## 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.
@@ -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
<a name=upload></a>
<a name="upload"></a>
## Upload Files
How can we read data when the date come from an uploaded file/s?.
HTML supports a form element ```<input type="File" ... > ``` to upload a single file and ```<input type="File" ... multiplr> ``` to upload multiple files.
@@ -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.
<a name=examples>
<a name="examples"></a>
## Examples
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.
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)

View File

@@ -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
- 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`.
<a name="read_header"></a>
## Reading HTTP Header fields
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).
<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:
```
@@ -102,59 +104,72 @@ Overview of the features
<a name="understand"></a>
#### Understanding HTTP 1.1 Request Headers
Access to the request headers permits the web server applications or APIs to perform optimizations and provide behavior that would not be possible without them for instance such as adapting the response according to the browser preferences.
This section summarizes the headers most often used; for more information, see the [HTTP 1.1 specification](https://httpwg.github.io/specs/), note that [RFC 2616 is dead](https://www.mnot.net/blog/2014/06/07/rfc2616_is_dead).
<a name="accept"></a>
* [Accept](https://httpwg.github.io/specs/rfc7231.html#header.accept)
- The "Accept" header field can be used by user agents (browser or other clients) to define response media types that are acceptable. Accept header fields can be used to indicate that the request is limited to a small set of desired types, as in the case of a request for an inline image.
For example, assume an APIs Learn4Kids can respond with XML or JSON data (JSON format have some advantages over XML, readability, parsing etc...), a client can define its preference using "Accept: application/json" to request data in JSON format, or "Accept: application/xml" to get XML format. In other case the server sends a not acceptable response. Note that the client can define an ordered list of accepted content types, including "*", the client will get the response and know the content type via the response header field "Content-Type". Related [Content-Negotiation]()
<a name="accept_charset"></a>
* [Accept-Charset](https://httpwg.github.io/specs/rfc7231.html#header.accept-charset)
- The "Accept-Charset" header field can be sent by a user agent (browser or other clients) to indicate which charsets are acceptable in textual response content (e.g., ISO-8859-1).
<a name="accept_encoding"></a>
* [Accept-Encoding](https://httpwg.github.io/specs/rfc7231.html#header.accept-encoding)
- The "Accept-Encoding" header field can be used by user agents (browser or other clients) to indicate which response content-codings (`gzip`, `compress`) are acceptable in the response. An "identity" token is used as a synonym for "no encoding" in order to communicate when no encoding is preferred. If the server receives this header, it is free to encode the page by using one of the content-encodings specified (usually to reduce transmission time), sending the `Content-Encoding` response header to indicate that it has done so.
<a name="accept_language"></a>
* [Accept-Language](https://httpwg.github.io/specs/rfc7231.html#header.accept-language)
- The "Accept-Language" header field can be used by user agents (browser or other client) to indicate the set of natural languages that are preferred in the response in case the server can produce representation in more than one language. The value of the header should be one of the standard language codes such as en, en-us, da, etc. See RFC 1766 for details (start at http://www.rfc-editor.org/ to get a current list of the RFC archive sites).
<a name="connection"></a>
* [Connection](https://httpwg.github.io/specs/rfc7230.html#header.connection)
- The "Connection" header field allows the sender to indicate desired control options for the current connection, for example if it can hanlde persistent HTTP connections.
By default HTTP/1.1 uses "persistent connections", allowing multiple requests and responses to be carried over a single connection. The "close" connection option is used to signal that a connection will not persist after the current request/response.
<a name="authorization"></a>
* [Authorization](https://httpwg.github.io/specs/rfc7235.html#header.authorization)
- The header is used by user agents to authenticate themselves when accessing password protected resources.
<a name="content-length"></a>
* [Content-Length](https://httpwg.github.io/specs/rfc7230.html#header.content-length)
- For messages that includes a payload body, the Content-Length field-value provides the framing information necessary to determine where the body (and message) ends.
<a name="cookie"></a>
* [Cookie](https://httpwg.github.io/specs/rfc6265.html)
- The Cookie header contains cookies received by the user agent in previous Set-Cookie headers. The origin server is free to ignore the Cookie header or use its contents for an application-specific purpose. (Related State Management).
<a name="host"></a>
* [Host](https://httpwg.github.io/specs/rfc7230.html#header.host)
- The "Host" header field provides the host and port information from the target URI, enabling the origin server to distinguish among resources while serving requests for multiple host names on a single IP address. In HTTP 1.1, browsers and other clients are required to specify this header, which indicates the host and port as given in the original URL.
<a name="if-modified-since"></a>
* [If-Modified-Since](https://httpwg.github.io/specs/rfc7232.html#header.if-modified-since)
- The "If-Modified-Since" header field makes a GET or HEAD request method conditional on the selected representation's modification date being more recent than the date provided in the field-value. Transfering of the selected representation's data is avoided if that data has not changed. So, indicates that the user agents wants the page only if it has been changes after the specified date. The server sends a 304 resource not modified if not has a newer result representation available.
<a name="if-unmodified-since"></a>
* [If-Unmodified-Since](https://httpwg.github.io/specs/rfc7232.html#header.if-unmodified-since)
- The "If-Unmodified-Since" header field makes the request method conditional on the selected representation's last modification date being earlier than or equal to the date provided in the field-value. The operation should succeed only if the document is older than the specified date.
Generally, If-Modified-Since is used for GET requests (“give me the document only if it is newer than my cached version”), whereas If-Unmodified-Since is used for PUT requests (“update this document only if nobody else has changed it since I generated it”).
<a name="referer"></a>
* [Referer](https://httpwg.github.io/specs/rfc7231.html#header.referer)
- The "Referer" header field allows the user agent to specify a URI reference for the resource from which the target URI was obtained (i.e., the "referrer", though the field name is misspelled). A user agent MUST NOT include the fragment and userinfo components of the URI reference [RFC3986], if any, when generating the Referer field value. This header indicates the URL of the referring Web page.
@@ -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.
<a name="user-agent"></a>
* [User-Agent](https://httpwg.github.io/specs/rfc7231.html#header.user-agent)
- The "User-Agent" header field contains information about the user agent of the request, which is often used by servers to help identify the scope of reported interoperability problems, to work around or tailor responses to avoid particular user agent limitations, and for analytics regarding browser or operating system use or device.
**Note**: the example shows the **WSF_EXECUTION** implementation, that will be used by the service launcher.
<a name="example"></a>
#### Building a Table of All Request Headers
The following [EWF service](/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).
@@ -276,6 +293,7 @@ end
```
<a name="compress"></a>
#### How to compress pages
To be completed.
@@ -284,7 +302,7 @@ To be completed.
#### Detecting Browser Types
The User-Agent header identifies the specific browser/client that is sending the request. The following code shows a [EWF service](/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.
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)
**Example**
An [EWF service](/doc/workbook/handling_request/headers/cgi_variables/application.e) that shows the CGI variables, creates a table showing the values of all the CGI variables.
Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/doc/workbook/handling_request/form.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md)
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](./form.md) :: [Generating Responses](../generating_response/generating_response.md)

View File

@@ -1,13 +1,4 @@
Introduction
Basic Concepts
Generating Plain Text
Generation HTML
The [Workbook](./workbook.md) lets you discover the EiffelWeb framework.
Handling Client Request:
Form Data
Request Heders
Query Parameters.
[Enter the documentation](./workbook.md)

View File

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

View 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

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

View 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

View File

@@ -10,11 +10,6 @@
</option>
<setting name="concurrency" value="thread"/>
<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="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"/>

View File

@@ -20,9 +20,10 @@ feature {NONE} -- Initialization
initialize
-- Initialize current service.
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

View File

@@ -17,10 +17,13 @@ feature -- Basic operations
execute
local
s: STRING
do
-- To send a response we need to setup, the status code and
-- the response headers.
s := "Hello World!"
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 + ").")
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

View File

@@ -1,35 +1,28 @@
<?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">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<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">
<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"/>
</option>
<setting name="console_application" value="true"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
</target>
<target name="simple_standalone" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
<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="thread"/>
<setting name="concurrency" value="scoop"/>
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf"/>
<cluster name="simple" location=".\" recursive="true"/>
</target>
<target name="simple_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="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">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">

View 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

View File

@@ -7,7 +7,6 @@
</option>
<setting name="concurrency" value="thread"/>
<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="http" location="..\..\library\network\protocol\http\http-safe.ecf"/>
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>

View 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

View 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

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

View 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

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

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

View File

@@ -1,7 +1,6 @@
<?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">
<target name="upload_image">
<root class="IMAGE_UPLOADER" feature="make"/>
<target name="upload_image_common">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/\.git$</exclude>
@@ -11,19 +10,26 @@
<debug name="standalone" enabled="true"/>
<assertions precondition="true" postcondition="true" check="true" invariant="true" supplier_precondition="true"/>
</option>
<setting name="concurrency" value="thread"/>
<setting name="concurrency" value="scoop"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="connector_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="http" location="..\..\library\network\protocol\http\http-safe.ecf" readonly="false"/>
<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="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"/>
</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>

View 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

View 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

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

View 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

View File

@@ -3,13 +3,25 @@ package http_client
project
http_client = "http_client-safe.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
-- title:
-- description:
-- tags:
-- license:
-- copyright:
-- link[doc]: "Documentation" http://
title: HTTP client
description: "[
Provides simple routines to perform http requests, and get associated response.
It has two implementations:
- using Eiffel cURL (i.e libcurl)
- 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

View File

@@ -5,11 +5,16 @@ project
conneg = "conneg.ecf"
note
-- title:
-- description:
-- tags:
-- license:
-- copyright:
-- link[doc]: "Documentation" http://
title: CONneg Content Negotiation
description: "[
CONneg is a library that provides utilities to select the best repesentation of a resource for a client where there are multiple representations available.
]"
collection: EWF
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

View File

@@ -5,11 +5,22 @@ project
http = "http.ecf"
note
-- title:
-- description:
-- tags:
-- license:
-- copyright:
-- link[doc]: "Documentation" http://
title: HTTP protocol
description: "[
Collection of interfaces related to HTTP protocol:
- header
- status codes, request methods
- 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

View File

@@ -38,7 +38,7 @@ feature {NONE} -- Initialization
do
set_name (a_name)
set_value(a_value)
set_max_age (-1)
unset_max_age
ensure
name_set: name = a_name
value_set: value = a_value
@@ -101,15 +101,6 @@ feature -- Access
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 the date represented by `a_string' a valid rfc1123 date?
local
@@ -119,10 +110,56 @@ feature -- Access
Result := not d.has_error and then d.rfc1123_string.same_string (a_string)
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
set_name (a_name: READABLE_STRING_8)
-- Set `name' with `a_name'.
-- Set `name' to `a_name'.
require
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)
@@ -133,7 +170,7 @@ feature -- Change Element
end
set_value (a_value: READABLE_STRING_8)
-- Set `value' with `a_value'.
-- Set `value' to `a_value'.
require
a_value_has_valid_characters: a_value /= Void and then has_valid_characters (a_value)
do
@@ -143,7 +180,7 @@ feature -- Change Element
end
set_expiration (a_date: READABLE_STRING_8)
-- Set `expiration' with `a_date'
-- Set `expiration' to RFC1123 date string `a_date'.
require
rfc1133_date: a_date /= Void and then is_valid_rfc1123_date (a_date)
do
@@ -153,7 +190,7 @@ feature -- Change Element
end
set_expiration_date (a_date: DATE_TIME)
-- Set `expiration' with `a_date'
-- Set `expiration' to `a_date'.
do
set_expiration (date_to_rfc1123_http_date_format (a_date))
ensure
@@ -161,7 +198,7 @@ feature -- Change Element
end
set_path (a_path: READABLE_STRING_8)
-- Set `path' with `a_path'
-- Set `path' to `a_path'.
do
path := a_path
ensure
@@ -169,7 +206,7 @@ feature -- Change Element
end
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
-- since they are not always handled by browser (for instance Chrome)
require
@@ -181,7 +218,7 @@ feature -- Change Element
end
set_secure (a_secure: BOOLEAN)
-- Set `secure' with `a_secure'
-- Set `secure' to `a_secure'.
do
secure := a_secure
ensure
@@ -189,7 +226,7 @@ feature -- Change Element
end
set_http_only (a_http_only: BOOLEAN)
-- Set `http_only' with `a_http_only'
-- Set `http_only' to `a_http_only'.
do
http_only := a_http_only
ensure
@@ -197,48 +234,29 @@ feature -- Change Element
end
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
max_age := a_max_age
ensure
max_age_set: max_age = a_max_age
end
mark_max_age
-- Set `include_max_age' to True.
-- Set `include_expires' to False.
-- Set-Cookie will include only Max-Age attribute and not Expires.
unset_max_age
-- Set `max_age' to -1.
do
include_max_age := True
include_expires := False
max_age := -1
ensure
max_age_true: include_max_age
expire_false: not include_expires
max_age_unset: max_age = -1
end
mark_expires
-- Set `include_expires' to True.
-- Set `include_max_age' to False
-- Set-Cookie will include only Expires attribute and not Max_Age.
unset_expiration
-- Set `expiration' to Void.
do
include_expires := True
include_max_age := False
expiration := Void
ensure
expires_true: include_expires
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
expiration_void: expiration = Void
end
feature {NONE} -- Date Utils
@@ -270,28 +288,14 @@ feature -- Output
s.append ("; Path=")
s.append (l_path)
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_integer (max_age)
end
@@ -339,7 +343,7 @@ feature {NONE} -- Constants
end
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)"
source: "[
Eiffel Software

View File

@@ -180,7 +180,9 @@ feature -- Header: adding
if line [line.count] = '%R' then
line.remove_tail (1)
end
add_header (line)
if not line.is_empty then
add_header (line)
end
end
end
end

View File

@@ -20,7 +20,7 @@ feature -- Test routines
l_cookie: HTTP_COOKIE
do
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
test_cookie_value_with_illegal_characters
@@ -42,7 +42,7 @@ feature -- Test routines
l_cookie: HTTP_COOKIE
do
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
test_cookie_full_attributes
@@ -55,7 +55,8 @@ feature -- Test routines
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=/; 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
test_cookie_include_expires
@@ -68,7 +69,6 @@ feature -- Test routines
l_cookie.set_path ("/")
l_cookie.set_secure (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"))
end
@@ -82,8 +82,8 @@ feature -- Test routines
l_cookie.set_path ("/")
l_cookie.set_secure (True)
l_cookie.set_http_only (True)
l_cookie.mark_max_age
assert("Expected", l_cookie.header_line.same_string ("Set-Cookie: user_id=u12345; Domain=www.example.com; Path=/; 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
test_cookie_defaults_and_http_only
@@ -92,7 +92,7 @@ feature -- Test routines
do
create l_cookie.make ("user_id", "u12345")
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
test_cookie_defaults_and_secure
@@ -101,7 +101,7 @@ feature -- Test routines
do
create l_cookie.make ("user_id", "u12345")
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
@@ -111,7 +111,7 @@ feature -- Test routines
do
create l_cookie.make ("user_id", "u12345")
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
@@ -121,7 +121,7 @@ feature -- Test routines
do
create l_cookie.make ("user_id", "u12345")
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
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"))
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

View File

@@ -5,11 +5,21 @@ project
notification_email = "notification_email.ecf"
note
-- title:
-- description:
-- tags:
-- license:
-- copyright:
-- link[doc]: "Documentation" http://
title: Notification Email
description: "[
Abstract interface to send message via various mailers:
- smtp
- sendmail
- 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

View File

@@ -508,9 +508,9 @@ feature -- Helper
new_session (a_uri: READABLE_STRING_8): HTTP_CLIENT_SESSION
local
cl: LIBCURL_HTTP_CLIENT
cl: DEFAULT_HTTP_CLIENT
do
create cl.make
create cl
Result := cl.new_session (a_uri)
Result.set_is_insecure (True)
Result.set_max_redirects (5)

View File

@@ -3,14 +3,17 @@ package openid
project
openid = "consumer/openid.ecf"
openid = "consumer/openid-safe.ecf"
demo = "consumer/demo/demo-safe.ecf"
note
title: Eiffel OpenID
description: OpenID library (for now only consumer)
tags: openid,security
description: OpenID consumer library
tags: openid,security,web,authentication,sso
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
-- copyright:
-- link[doc]: "Documentation" http://
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/security/http_authorization
link[doc]: "Documentation" https://github.com/EiffelWebFramework/EWF/tree/master/library/security/http_authorization/README.md
end

View File

@@ -5,11 +5,16 @@ project
http_authorization = "http_authorization.ecf"
note
-- title:
-- description:
-- tags:
-- license:
-- copyright:
-- link[doc]: "Documentation" http://
title: HTTP Authorization
description: "[
Class to manipulate HTTP 'Authorization' header value.
]"
collection: EWF
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

View File

@@ -23,8 +23,8 @@ feature {NONE} -- Initialization
local
n: INTEGER
p: like pool
do
n := max_concurrent_connections (server)
do
n := max_concurrent_connections (server).max (1) -- At least one processor!
create p.make (n)
initialize_pool (p, n)
pool := p

View File

@@ -25,20 +25,27 @@ feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation
release
-- <Precursor>
local
d: STRING
d: detachable STRING
do
if attached internal_client_socket as l_socket then
d := l_socket.descriptor.out
else
d := "N/A"
end
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 + "}")
end
Precursor {HTTPD_REQUEST_HANDLER_I}
release_pool_item
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

View File

@@ -23,7 +23,7 @@ feature {NONE} -- Initialization
local
n: INTEGER
do
n := max_concurrent_connections (server)
n := max_concurrent_connections (server).max (1) -- At least one thread!
create pool.make (n.to_natural_32)
end

View File

@@ -18,21 +18,28 @@ inherit
feature {HTTPD_CONNECTION_HANDLER_I} -- Basic operation
release
-- <Precursor>
local
d: STRING
d: detachable STRING
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")
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 + "}")
end
Precursor {HTTPD_REQUEST_HANDLER_I}
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,11 +24,29 @@
</condition>
</library>
<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">
<file_rule>
<exclude>/concurrency$</exclude>
<exclude>/no_ssl$</exclude>
<exclude>/ssl$</exclude>
<exclude>/network$</exclude>
</file_rule>
<cluster name="no_ssl" location="$|no_ssl\" recursive="true">
<condition>

View File

@@ -11,7 +11,6 @@
</option>
<setting name="concurrency" value="thread"/>
<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_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl.ecf">
<condition>
@@ -24,12 +23,29 @@
</condition>
</library>
<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">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/concurrency$</exclude>
<exclude>/no_ssl$</exclude>
<exclude>/ssl$</exclude>
<exclude>/network$</exclude>
</file_rule>
<cluster name="no_ssl" location="$|no_ssl\" recursive="true">
<condition>

View File

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

View File

@@ -9,11 +9,24 @@ deferred class
inherit
HTTPD_DEBUG_FACILITIES
HTTPD_LOGGER_CONSTANTS
HTTPD_SOCKET_FACTORY
feature {NONE} -- Initialization
make
make (a_request_settings: HTTPD_REQUEST_SETTINGS)
do
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
reset
@@ -59,7 +72,7 @@ feature -- Access
do
s := internal_client_socket
if s = Void then
create s.make_empty
s := new_client_socket (is_secure)
internal_client_socket := s
end
Result := s
@@ -107,16 +120,36 @@ feature -- Access
feature -- Settings
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?
do
Result := {HTTPD_SERVER}.is_persistent_connection_supported
end
Result := {HTTPD_SERVER}.is_persistent_connection_supported and then max_keep_alive_requests > 0
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.
-- Default: 5 sec.
feature -- Status report
@@ -162,9 +195,10 @@ feature -- Execution
local
l_socket: like client_socket
l_exit: BOOLEAN
n: INTEGER
n,m: INTEGER
do
l_socket := client_socket
l_socket.set_recv_timeout (socket_recv_timeout)
check
socket_attached: l_socket /= Void
socket_valid: l_socket.is_open_read and then l_socket.is_open_write
@@ -172,27 +206,40 @@ feature -- Execution
from
-- Process persistent connection as long the socket is not closed.
n := 0
m := max_keep_alive_requests
is_next_persistent_connection_supported := True
until
l_exit
loop
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.
execute_request
execute_request (n > 1)
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 has_error or l_socket.is_closed or not l_socket.is_open_read
reset_request
end
if l_exit and has_error and not l_socket.is_closed then
l_socket.close
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
is_connected: is_connected
reuse_connection_when_possible: a_is_reusing_connection implies is_persistent_connection_supported
local
l_remote_info: detachable like remote_info
l_socket: like client_socket
l_is_ready: BOOLEAN
i: INTEGER
do
l_socket := client_socket
check
@@ -208,21 +255,16 @@ feature -- Execution
dbglog (generator + ".execute_request socket=" + l_socket.descriptor.out + " ENTER")
end
--| TODO: add configuration options for socket timeout.
--| set by default 5 seconds.
-- l_socket.set_timeout (persistent_connection_timeout) -- 5 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
if a_is_reusing_connection then
--| set by default 5 seconds.
l_socket.set_recv_timeout (keep_alive_timeout) -- in seconds!
l_is_ready := l_socket.ready_for_reading
check not l_socket.is_closed end
i := i - 1
else
l_is_ready := True
end
if l_is_ready then
l_socket.set_recv_timeout (socket_recv_timeout) -- FIXME: return a 408 Request Timeout response ..
create l_remote_info
if attached l_socket.peer_address as l_addr then
l_remote_info.addr := l_addr.host_address.host_address
@@ -242,10 +284,13 @@ feature -- Execution
if l_is_ready then
-- check catch_bad_incoming_connection: False end
if is_verbose then
log ("ERROR: invalid HTTP incoming request")
log (request_header + "%NWARNING: invalid HTTP incoming request", warning_level)
end
end
else
if is_verbose then
log (request_header, information_level)
end
process_request (l_socket)
end
debug ("dbglog")
@@ -289,7 +334,12 @@ feature -- Parsing
do
create txt.make (64)
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_character ('%N')
analyze_request_line (l_request_line)
@@ -297,16 +347,17 @@ feature -- Parsing
has_error := True
end
l_is_verbose := is_verbose
if not has_error or l_is_verbose then
-- if `is_verbose' we can try to print the request, even if it is a bad HTTP request
if not has_error then
from
line := next_line (a_socket)
until
line = Void or end_of_stream
line = Void or end_of_stream or has_error
loop
n := line.count
if l_is_verbose then
log (line)
debug ("ew_standalone")
if l_is_verbose then
log (line, debug_level)
end
end
pos := line.index_of (':', 1)
if pos > 0 then
@@ -353,9 +404,11 @@ feature -- Parsing
local
n, pos, next_pos: INTEGER
do
if is_verbose then
log ("%N## Parse HTTP request line ##")
log (line)
debug ("ew_standalone")
if is_verbose then
log ("%N## Parse HTTP request line ##", debug_level)
log (line, debug_level)
end
end
pos := line.index_of (' ', 1)
method := line.substring (1, pos - 1)
@@ -372,15 +425,31 @@ feature -- Parsing
next_line (a_socket: HTTPD_STREAM_SOCKET): detachable STRING
-- Next line fetched from `a_socket' is available.
require
not_has_error: not has_error or is_verbose
is_readable: a_socket.is_open_read
local
retried: BOOLEAN
do
if retried then
has_error := True
Result := Void
elseif a_socket.socket_ok then
elseif a_socket.readable then
a_socket.read_line_thread_aware
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
rescue
retried := True
@@ -399,13 +468,17 @@ feature -- Output
logger_set: logger = a_logger
end
log (m: STRING)
log (m: STRING; a_level: INTEGER)
-- Log message `m'.
require
is_verbose: is_verbose
do
if attached logger as l_logger then
l_logger.log (m)
else
io.put_string (m + "%N")
if is_verbose and (verbose_level & a_level) = a_level then
if attached logger as l_logger then
l_logger.log (m)
else
io.put_string (m + "%N")
end
end
end

View File

@@ -37,7 +37,7 @@ feature {NONE} -- Initialization
build_controller
-- Build `controller'.
do
create controller
create <NONE> controller
end
initialize
@@ -51,6 +51,9 @@ feature -- Access
is_verbose: BOOLEAN
-- Is verbose for output messages.
verbose_level: INTEGER
-- Verbosity of output.
configuration: HTTPD_CONFIGURATION
-- Associated server configuration.
@@ -100,7 +103,17 @@ feature -- Execution
apply_configuration
is_terminated := False
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
is_shutdown_requested := False
listen
@@ -150,7 +163,7 @@ feature -- Listening
if not l_listening_socket.is_bound 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
else
l_http_port := l_listening_socket.port
@@ -159,9 +172,9 @@ feature -- Listening
l_listening_socket.listen (configuration.max_tcp_clients)
if is_verbose 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
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
on_launched (l_http_port)
@@ -312,6 +325,7 @@ feature -- Configuration change
is_not_launched: not is_launched
do
is_verbose := configuration.is_verbose
verbose_level := configuration.verbose_level
end
feature -- Output

View File

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

View File

@@ -12,6 +12,8 @@ class
create
make_server_by_address_and_port,
make_server_by_port,
make_client_by_address_and_port,
make_client_by_port,
make_from_separate,
make_empty
@@ -30,6 +32,16 @@ feature {NONE} -- Initialization
create {TCP_STREAM_SOCKET} socket.make_server_by_port (a_port)
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)
require
descriptor_available: s.descriptor_available
@@ -50,6 +62,7 @@ feature {NONE} -- Initialization
feature -- Change
set_timeout (n: INTEGER)
-- Set timeout to `n' seconds.
do
if attached {NETWORK_STREAM_SOCKET} socket as l_socket then
l_socket.set_timeout (n)
@@ -70,6 +83,22 @@ feature -- Change
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
last_string: STRING
@@ -164,6 +193,11 @@ feature -- Status Report
end
end
exists: BOOLEAN
do
Result := socket.exists
end
is_blocking: BOOLEAN
do
Result := socket.is_blocking
@@ -176,6 +210,13 @@ feature -- Status Report
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
do
if attached {NETWORK_SOCKET} socket as l_socket then
@@ -220,6 +261,16 @@ feature -- Status Report
end
end
connect
do
socket.connect
end
close
do
socket.close
end
listen (a_queue: INTEGER)
do
socket.listen (a_queue)

View File

@@ -17,36 +17,66 @@ inherit
ready_for_writing,
ready_for_reading,
try_ready_for_reading,
put_readable_string_8
put_readable_string_8,
make_empty
end
create
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}
make
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
l_socket: SSL_TCP_STREAM_SOCKET
do
create l_socket.make_server_by_address_and_port (an_address, a_port)
l_socket.set_tls_protocol (a_ssl_protocol)
socket := l_socket
set_certificates (a_crt, a_key)
set_certificates (a_crt_fn, a_key_fn)
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
l_socket: SSL_TCP_STREAM_SOCKET
do
create l_socket.make_server_by_port (a_port)
l_socket.set_tls_protocol (a_ssl_protocol)
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
feature -- Output
@@ -114,15 +144,15 @@ feature -- Status Report
feature {HTTPD_STREAM_SOCKET} -- Implementation
set_certificates (a_crt: STRING; a_key: STRING)
local
a_file_name: FILE_NAME
set_certificates (a_crt_filename, a_key_filename: detachable READABLE_STRING_GENERAL)
do
if attached {SSL_NETWORK_STREAM_SOCKET} socket as l_socket then
create a_file_name.make_from_string (a_crt)
l_socket.set_certificate_file_name (a_file_name)
create a_file_name.make_from_string (a_key)
l_socket.set_key_file_name (a_file_name)
if a_crt_filename /= Void then
l_socket.set_certificate_file_name (a_crt_filename)
end
if a_key_filename /= Void then
l_socket.set_key_file_name (a_key_filename)
end
end
end

View File

@@ -12,6 +12,7 @@ inherit
create
make_server_by_address_and_port, make_server_by_port,
make_client_by_address_and_port, make_client_by_port,
make_empty
create {SSL_NETWORK_STREAM_SOCKET}

View File

@@ -12,9 +12,13 @@ inherit
make
end
TCP_STREAM_SOCKET_EXT
create
make_server_by_address_and_port,
make_server_by_port,
make_client_by_address_and_port,
make_client_by_port,
make_from_separate,
make_empty

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,13 +24,10 @@ create
feature {NONE} -- Initialization
make_with_connector (conn: like connector)
make_with_connector (a_request_settings: HTTPD_REQUEST_SETTINGS; conn: like connector)
do
make
make (a_request_settings)
connector := conn
-- if conn /= Void then
-- set_is_verbose (is_connector_verbose (conn))
-- end
end
feature -- Access
@@ -56,11 +53,6 @@ feature -- SCOOP helpers
Result := conn.base
end
is_connector_verbose (conn: separate WGI_STANDALONE_CONNECTOR [G]): BOOLEAN
do
Result := conn.is_verbose
end
feature -- Request processing
process_request (a_socket: HTTPD_STREAM_SOCKET)
@@ -87,7 +79,7 @@ feature -- Request processing
else
l_output.set_http_version (version)
end
res.set_is_persistent_connection_supported ({HTTPD_SERVER}.is_persistent_connection_supported)
res.set_is_persistent_connection_supported (is_persistent_connection_supported and is_next_persistent_connection_supported)
res.set_is_persistent_connection_requested (is_persistent_connection_requested)
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 (version, "SERVER_PROTOCOL", 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
l_base := base

View File

@@ -1,5 +1,5 @@
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$"
revision: "$Revision$"
@@ -14,19 +14,23 @@ feature -- Access
connector: detachable separate WGI_STANDALONE_CONNECTOR [G]
-- httpd solution.
request_settings: HTTPD_REQUEST_SETTINGS
-- Settings specific to request handling.
feature -- Element change
set_connector (conn: like connector)
update_with (conn: like connector; a_conf: separate HTTPD_CONFIGURATION)
-- Set `connector' with `conn'.
do
connector := conn
request_settings := a_conf.request_settings
end
feature -- Factory
new_handler: separate WGI_HTTPD_REQUEST_HANDLER [G]
do
create Result.make_with_connector (connector)
create Result.make_with_connector (request_settings, connector)
end
note

View File

@@ -1,9 +1,9 @@
note
description: "[
Standalone Web Server connector
Standalone Web Server connector.
]"
date: "$Date$"
revision: "$Revision$"
date: "$Date: 2016-08-06 13:34:52 +0200 (sam., 06 août 2016) $"
revision: "$Revision: 99106 $"
class
WGI_STANDALONE_CONNECTOR [G -> WGI_EXECUTION create make end]
@@ -20,18 +20,18 @@ feature {NONE} -- Initialization
make
-- Create current standalone connector.
local
fac: separate WGI_HTTPD_REQUEST_HANDLER_FACTORY [G]
fac: like request_handler_factory
do
-- Callbacks
create on_launched_actions
-- Server
create fac
create <NONE> fac
request_handler_factory := fac
create server.make (fac)
create observer
create <NONE> observer
configuration := server_configuration (server)
controller := server_controller (server)
set_factory_connector (Current, fac)
initialize_server (server)
end
@@ -51,9 +51,9 @@ feature {NONE} -- Separate helper
a_server.set_observer (observer)
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
fac.set_connector (conn)
fac.update_with (conn, a_conf)
end
server_configuration (a_server: like server): like configuration
@@ -63,17 +63,26 @@ feature {NONE} -- Separate helper
feature -- Access
name: STRING_8 = "httpd"
name: STRING_8
-- Name of Current connector
once
Result := "httpd"
end
version: STRING_8 = "0.1"
version: STRING_8
-- Version of Current connector
once
Result := "1.0"
end
feature -- Access
server: separate HTTPD_SERVER
-- HTTPd server object.
request_handler_factory: separate WGI_HTTPD_REQUEST_HANDLER_FACTORY [G]
-- Factory for request handlers.
controller: separate HTTPD_CONTROLLER
-- Controller used to shutdown server.
@@ -97,9 +106,6 @@ feature -- Status report
-- Listening port.
--| 0: not launched
is_verbose: BOOLEAN
-- Is verbose?
feature -- Callbacks
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)
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
@@ -190,18 +202,22 @@ feature {NONE} -- Implementation
Result := a_server.controller
end
configure_server (a_configuration: like configuration)
apply_configuration (a_configuration: like configuration)
local
v: BOOLEAN
do
if a_configuration.is_verbose then
if attached base as l_base then
v := a_configuration.is_verbose
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")
end
end
update_factory (Current, request_handler_factory, a_configuration)
end
launch_server (a_server: like server)
do
configure_server (a_server.configuration)
apply_configuration (a_server.configuration)
a_server.launch
end
@@ -229,13 +245,17 @@ feature {NONE} -- Implementation: element change
set_is_verbose_on_configuration (b: BOOLEAN; cfg: like configuration)
do
is_verbose := b
cfg.set_is_verbose (b)
end
set_is_secure_on_configuration (b: BOOLEAN; cfg: like configuration)
do
cfg.set_is_secure (b)
end
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)"
source: "[
Eiffel Software

View File

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

View File

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

View File

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

View File

@@ -24,7 +24,7 @@ feature {NONE} -- Initialization
set_source (a_source)
end
feature {WGI_STANDALONE_CONNECTOR, WGI_SERVICE} -- Nino
feature {WGI_STANDALONE_CONNECTOR, WGI_SERVICE, WGI_STANDALONE_CONNECTOR_EXPORTER} -- Standalone
set_source (i: like source)
do

View File

@@ -108,7 +108,6 @@ feature -- Header output operation
l_connection := s.substring (i + 12, j - 1)
l_connection.adjust
if
not is_http_version_1_0 and
not l_connection.is_case_insensitive_equal_general ("close")
then
s.replace_substring ("Connection: close", i + 1, j - 1)

View File

@@ -16,7 +16,7 @@
<library name="encoder" location="..\..\..\..\text\encoder\encoder-safe.ecf"/>
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
<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="implementation" location="$|implementation\" hidden="true"/>
</cluster>

View File

@@ -15,7 +15,7 @@
<library name="encoder" location="..\..\..\..\text\encoder\encoder.ecf"/>
<library name="ewsgi" location="..\..\ewsgi.ecf" readonly="false"/>
<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="implementation" location="$|implementation\" hidden="true"/>
</cluster>

View File

@@ -10,12 +10,11 @@
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="connector_standalone" location="standalone-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">
<debug name="dbglog" enabled="true"/>
</option>
</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"/>
<cluster name="tests" location="tests\" recursive="true"/>
</target>

View File

@@ -3,21 +3,28 @@ package ewsgi
project
ewsgi = "ewsgi-safe.ecf"
ewsgi = "ewsgi.ecf"
ewsgi_spec = "ewsgi_spec-safe.ecf"
ewsgi_spec = "ewsgi_spec.ecf"
connector_cgi = "connectors/cgi/cgi-safe.ecf"
connector_cgi = "connectors/cgi/cgi.ecf"
connector_libfcgi = "connectors/libfcgi/libfcgi-safe.ecf"
connector_libfcgi = "connectors/libfcgi/libfcgi.ecf"
connector_nino = "connectors/nino/nino-safe.ecf"
connector_nino = "connectors/nino/nino.ecf"
connector_null = "connectors/null/null-safe.ecf"
connector_null = "connectors/null/null.ecf"
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
title: EWSGI
description: EWSGI specification, and a few connectors.
tags: web, httpd, ewf
license: Eiffel Forum v2
description: "[
Eiffel Web Server Gateway Interface (EWSGI) specification, and a few connectors.
]"
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

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