From 70288923744a45ced4c8c5ad6c0bec4c2ffbd07d Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Fri, 12 May 2017 14:55:02 +0200 Subject: [PATCH] Removed unwanted committed files. --- .../examples/custom/js_custom_widget.rc | 6 - .../wsf_js_widget/examples/demo/demo.rc | 6 - ewf.diff | 14185 ---------------- examples/_update_needed/filter/filter.rc | 6 - examples/form/form.rc | 6 - examples/rest/licence_manager/ewf.ini | 4 - .../rest/restbucks_CRUD/client/client.exe | Bin 1922560 -> 0 bytes examples/rest/restbucks_CRUD/restbucks.rc | 6 - examples/simple_ssl/exception_trace.log | 0 .../000c3a3555f3569845c4174640cba1c5.jpg | Bin 706292 -> 0 bytes .../0a4fb1d65857fe42527a75095ca35185.jpg | Bin 2999515 -> 0 bytes examples/upload_image/upload_image.rc | 6 - library/network/protocol/http/tests/tests.rc | 6 - .../client/example/ws_client/ws_client.rc | 6 - library/network/websocket/server/server.py | 60 - .../process/external_mailer_process.e | 19 - .../process/external_mailer_process_factory.e | 48 - .../until_16_05/external_mailer_process.e | 19 - .../external_mailer_process_factory.e | 38 - .../smtp/ssl/notification_ssl_smtp_mailer.e | 41 - .../smtp/ssl/ssl_smtp_protocol.e | 36 - library/server/wsf/tests/wsf_tests.rc | 6 - .../error/src/error_handler.e-ok20160107 | 528 - restbucks.rc | 6 - tools/estudio_wizard/test.cb | 4 - tools/estudio_wizard/wizard.cb | 1 - 26 files changed, 15043 deletions(-) delete mode 100644 draft/library/server/wsf_js_widget/examples/custom/js_custom_widget.rc delete mode 100644 draft/library/server/wsf_js_widget/examples/demo/demo.rc delete mode 100644 ewf.diff delete mode 100644 examples/_update_needed/filter/filter.rc delete mode 100644 examples/form/form.rc delete mode 100644 examples/rest/licence_manager/ewf.ini delete mode 100644 examples/rest/restbucks_CRUD/client/client.exe delete mode 100644 examples/rest/restbucks_CRUD/restbucks.rc delete mode 100644 examples/simple_ssl/exception_trace.log delete mode 100644 examples/upload_image/htdocs/files/000c3a3555f3569845c4174640cba1c5.jpg delete mode 100644 examples/upload_image/htdocs/files/0a4fb1d65857fe42527a75095ca35185.jpg delete mode 100644 examples/upload_image/upload_image.rc delete mode 100644 library/network/protocol/http/tests/tests.rc delete mode 100644 library/network/websocket/client/example/ws_client/ws_client.rc delete mode 100644 library/network/websocket/server/server.py delete mode 100644 library/runtime/process/notification_email/process/external_mailer_process.e delete mode 100644 library/runtime/process/notification_email/process/external_mailer_process_factory.e delete mode 100644 library/runtime/process/notification_email/process/until_16_05/external_mailer_process.e delete mode 100644 library/runtime/process/notification_email/process/until_16_05/external_mailer_process_factory.e delete mode 100644 library/runtime/process/notification_email/smtp/ssl/notification_ssl_smtp_mailer.e delete mode 100644 library/runtime/process/notification_email/smtp/ssl/ssl_smtp_protocol.e delete mode 100644 library/server/wsf/tests/wsf_tests.rc delete mode 100644 library/utility/general/error/src/error_handler.e-ok20160107 delete mode 100644 restbucks.rc delete mode 100644 tools/estudio_wizard/test.cb delete mode 100644 tools/estudio_wizard/wizard.cb diff --git a/draft/library/server/wsf_js_widget/examples/custom/js_custom_widget.rc b/draft/library/server/wsf_js_widget/examples/custom/js_custom_widget.rc deleted file mode 100644 index b0ec159c..00000000 --- a/draft/library/server/wsf_js_widget/examples/custom/js_custom_widget.rc +++ /dev/null @@ -1,6 +0,0 @@ -#include - -STRINGTABLE -BEGIN - 1 "This Program was made using EiffelStudio using Visual Studio C++" -END diff --git a/draft/library/server/wsf_js_widget/examples/demo/demo.rc b/draft/library/server/wsf_js_widget/examples/demo/demo.rc deleted file mode 100644 index b0ec159c..00000000 --- a/draft/library/server/wsf_js_widget/examples/demo/demo.rc +++ /dev/null @@ -1,6 +0,0 @@ -#include - -STRINGTABLE -BEGIN - 1 "This Program was made using EiffelStudio using Visual Studio C++" -END diff --git a/ewf.diff b/ewf.diff deleted file mode 100644 index 52bb2c61..00000000 --- a/ewf.diff +++ /dev/null @@ -1,14185 +0,0 @@ -diff --git a/doc/readme.md b/doc/readme.md -new file mode 100644 -index 0000000..26e5c0b ---- /dev/null -+++ b/doc/readme.md -@@ -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) -+ -diff --git a/doc/wiki/Spec-server-architecture.md b/doc/wiki/Spec-server-architecture.md -index 2960af9..e44f4de 100644 ---- a/doc/wiki/Spec-server-architecture.md -+++ b/doc/wiki/Spec-server-architecture.md -@@ -1,3 +1,3 @@ - ## Diagram: Overview of the server architecture ## - --![server_architecture.png](server_architecture.png) -\ No newline at end of file -+![server_architecture.png](./server_architecture.png) -diff --git a/doc/workbook/basics/basics.md b/doc/workbook/basics/basics.md -index f570644..698878b 100644 ---- a/doc/workbook/basics/basics.md -+++ b/doc/workbook/basics/basics.md -@@ -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) - - -- -+ -+ - ## 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,16 +92,15 @@ 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** - **WSF_CGI_SERVICE_LAUNCHER** --**WSF_NINO_SERVICE_LAUNCHER** - **WSF_LIBFCGI_SERVICE_LAUNCHER** - - A basic EWF service inherits from **WSF_DEFAULT_SERVICE**, which has a formal generic that should conform to **WSF_EXECUTION** class with a `make' creation procedure, in our case the class **APPLICATION_EXECUTION**. -@@ -109,11 +109,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 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 +143,18 @@ end - - ``` - --##### 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 Service to Generate HTML. - To generate HTML, it's needed - -@@ -193,7 +196,10 @@ feature -- Basic operations - - end - ``` --##### 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``` -@@ -202,5 +208,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) - -diff --git a/doc/workbook/basics/simple_html/apache_config/Readme.md b/doc/workbook/basics/simple_html/apache_config/Readme.md -index 448eb14..c2fd077 100644 ---- a/doc/workbook/basics/simple_html/apache_config/Readme.md -+++ b/doc/workbook/basics/simple_html/apache_config/Readme.md -@@ -1,31 +1,32 @@ --##Run simple_html example on Apache with FCGI on Windows. -+Nav: [Workbook](../../../workbook.md) :: [Basic concepts](../../../basics/basics.md) - -+## Run simple_html example on Apache with FCGI on Windows. - - --####Prerequisites -+#### Prerequisites - - * This tutorial was written for people working under Windows environment, and using Apache Server with FCGI connector - * 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) -diff --git a/doc/workbook/basics/simple_html/simple_html.rc b/doc/workbook/basics/simple_html/simple_html.rc -deleted file mode 100644 -index b0ec159..0000000 ---- a/doc/workbook/basics/simple_html/simple_html.rc -+++ /dev/null -@@ -1,6 +0,0 @@ --#include -- --STRINGTABLE --BEGIN -- 1 "This Program was made using EiffelStudio using Visual Studio C++" --END -diff --git a/doc/workbook/deployment.md b/doc/workbook/deployment.md -deleted file mode 100644 -index 3f86da9..0000000 ---- a/doc/workbook/deployment.md -+++ /dev/null -@@ -1,163 +0,0 @@ --EWF Deployment --============== -- --#Apache on Windows# -- --1. Apache Install --2. Deploying EWF CGI --3. CGI overview -- 1. Build EWF application -- 2. Copy the generated exe file and the www content .htaccess CGI --4. Deploying EWF FCGI --5. FCGI overview -- 1. Build EWF application -- 2. Copy the generated exe file and the www content.htaccess CGI -- -- -- --##Apache on Windows -- --###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 -- --####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. -- --* Build EWF application -- -- ec -config [app.ecf] -target [app_cgi] -finalize -c_compile -project_path -- -- -->Note: change app.ecf and target app_cgi based on your own configuration. -- --* Copy the generated exe file and the www content -- --Copy the app.exe and the folder _www_ into a folder served by apache2, for example under. -- -- -- /htdocs. -- -- = path to your apache installation -- -- Edit httpd.conf under c://conf -- -- DocumentRoot "c://htdocs" -- -- /htdocs"> -- AllowOverride All -- -- Require all granted -- this is required in Apache 2.4.4 -- -- --Check that you have the following modules enabled -- -- LoadModule cgi_module modules/mod_cgi.so -- LoadModule rewrite_module modules/mod_rewrite.so -- --####Tip: -->To check the syntax of your httpd.conf file. From command line run the following -- -- $>httpd - t -- -- -->.htaccess CGI -- http://perishablepress.com/stupid-htaccess-tricks/ -- --####.htaccess -- -- Options +ExecCGI +Includes +FollowSymLinks -Indexes -- AddHandler cgi-script exe -- -- -- RewriteEngine on -- -- RewriteRule ^$ $service [L] -- -- RewriteCond %{REQUEST_FILENAME} !-f -- RewriteCond %{REQUEST_FILENAME} !-d -- RewriteCond %{REQUEST_URI} !$service -- RewriteRule ^(.*)$ $service/$1 -- -- RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] -- Replace $service with the name of your executable service, for example app_service.exe -- -- --####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 -->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 -- -- ec -config [app.ecf] -target [app_fcgi] -finalize -c_compile -project_path . -- -->Note: change app.ecf and target app_fcgi based on your own configuration. -- --* Copy the generated exe file and the www content -- --Copy the app.exe and the folder "www" into a folder served by apache2, for example under -- -- /htdocs. -- -- = path to your apache installation -- -- Edit httpd.conf under c://conf -- -- DocumentRoot "c://htdocs" -- -- /htdocs"> -- AllowOverride All -- -- Require all granted -- this is required in Apache 2.4.4 -- -- -->Check that you have the following modules enabled -- -- LoadModule rewrite_module modules/mod_rewrite.so -- LoadModule fcgid_module modules/mod_fcgid.so -- -->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 -- -- Options +ExecCGI +Includes +FollowSymLinks -Indexes -- -- -- AddHandler fcgid-script .ews -- FcgidWrapper $FULL_PATH/$service .ews -- -- -- -- -- RewriteEngine on -- -- RewriteBase / -- RewriteRule ^$ service.ews [L] -- -- RewriteCond %{REQUEST_FILENAME} !-f -- RewriteCond %{REQUEST_FILENAME} !-d -- RewriteCond %{REQUEST_URI} !=/favicon.ico -- RewriteCond %{REQUEST_URI} !service.ews -- RewriteRule ^(.*)$ service.ews/$1 -- -- -- RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] -- -- --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. -- -- -- -- -diff --git a/doc/workbook/deployment/readme.md b/doc/workbook/deployment/readme.md -new file mode 100644 -index 0000000..91a9179 ---- /dev/null -+++ b/doc/workbook/deployment/readme.md -@@ -0,0 +1,189 @@ -+Nav: [Workbook](../workbook.md) -+ -+EWF Deployment -+============== -+ -+# Apache on Windows# -+ -+1. Apache Install -+2. Deploying EWF CGI -+3. CGI overview -+ 1. Build EWF application -+ 2. Copy the generated exe file and the www content .htaccess CGI -+4. Deploying EWF FCGI -+5. FCGI overview -+ 1. Build EWF application -+ 2. Copy the generated exe file and the www content.htaccess CGI -+ -+ -+ -+## Apache on Windows -+ -+### Apache Install -+ -+>Check the correct version (Win 32 or Win64) -+>Apache Version: Apache 2.4.4 -+>Windows: http://www.apachelounge.com/download/ -+ -+note: on linux (debian), use -+> sudo apt-get install apache2 -+ -+#### Deploying EWF CGI -+ -+#### 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. -+ -+* Build EWF application -+ -+ ec -config [app.ecf] -target [app_cgi] -finalize -c_compile -project_path -+ -+ -+>Note: change app.ecf and target app_cgi based on your own configuration. -+ -+* Copy the generated exe file and the www content -+ -+Copy the app.exe and the folder _www_ into a folder served by apache2, for example under. -+ -+ -+ /htdocs. -+ -+ = path to your apache installation -+ -+ Edit httpd.conf under c://conf -+ -+ DocumentRoot "c://htdocs" -+ -+ /htdocs"> -+ AllowOverride All -- -+ Require all granted -- this is required in Apache 2.4.4 -+ -+ -+Check that you have the following modules enabled -+ -+ LoadModule cgi_module modules/mod_cgi.so -+ LoadModule rewrite_module modules/mod_rewrite.so -+ -+#### Tip: -+>To check the syntax of your httpd.conf file. From command line run the following -+ -+ $>httpd - t -+ -+ -+>.htaccess CGI -+ http://perishablepress.com/stupid-htaccess-tricks/ -+ -+#### .htaccess -+ -+ Options +ExecCGI +Includes +FollowSymLinks -Indexes -+ AddHandler cgi-script exe -+ -+ -+ RewriteEngine on -+ -+ RewriteRule ^$ $service [L] -+ -+ RewriteCond %{REQUEST_FILENAME} !-f -+ RewriteCond %{REQUEST_FILENAME} !-d -+ RewriteCond %{REQUEST_URI} !$service -+ RewriteRule ^(.*)$ $service/$1 -+ -+ RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] -+ Replace $service with the name of your executable service, for example app_service.exe -+ -+ -+#### 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/ -+ -+note: on linux (debian), use -+> sudo apt-get install libapache2-mod-fastcgi -+ -+#### 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 -+ -+ ec -config [app.ecf] -target [app_fcgi] -finalize -c_compile -project_path . -+ -+>Note: change app.ecf and target app_fcgi based on your own configuration. -+ -+* Copy the generated exe file and the www content -+ -+Copy the app.exe and the folder "www" into a folder served by apache2, for example under -+ -+ /htdocs. -+ -+ = path to your apache installation -+ -+ Edit httpd.conf under c://conf -+ -+ DocumentRoot "c://htdocs" -+ -+ /htdocs"> -+ AllowOverride All -- -+ Require all granted -- this is required in Apache 2.4.4 -+ -+ -+>Check that you have the following modules enabled -+ -+ LoadModule rewrite_module modules/mod_rewrite.so -+ LoadModule fcgid_module modules/mod_fcgid.so -+ -+>NOTE: By default Apache does not come with fcgid module, so you will need to download it, and put the module under Apache2/modules -+ -+It is also possible to set various parameters in the apache site configuration file such as: -+``` -+ -+ # FcgidIdleTimeout 600 -+ # FcgidBusyScanInterval 120 -+ # FcgidProcessLifeTime 3600 -+ # FcgidMaxProcesses 5 -+ # FcgidMaxProcessesPerClass 100 -+ # FcgidMinProcessesPerClass 100 -+ # FcgidConnectTimeout 8 -+ # FcgidIOTimeout 60 -+ # FcgidBusyTimeout 1200 -+ -+``` -+See https://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html for more information. -+ -+# .htaccess FCGI -+ -+``` -+http://perishablepress.com/stupid-htaccess-tricks/ -+``` -+ -+#### .htaccess -+ -+ Options +ExecCGI +Includes +FollowSymLinks -Indexes -+ -+ -+ AddHandler fcgid-script .ews -+ FcgidWrapper $FULL_PATH/$service .ews -+ -+ -+ -+ -+ RewriteEngine on -+ -+ RewriteBase / -+ RewriteRule ^$ service.ews [L] -+ -+ RewriteCond %{REQUEST_FILENAME} !-f -+ RewriteCond %{REQUEST_FILENAME} !-d -+ RewriteCond %{REQUEST_URI} !=/favicon.ico -+ RewriteCond %{REQUEST_URI} !service.ews -+ RewriteRule ^(.*)$ service.ews/$1 -+ -+ -+ RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L] -+ -+ -+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) -diff --git a/doc/workbook/generating_response/generating_response.md b/doc/workbook/generating_response/generating_response.md -index 4d63cdf..977daf7 100644 ---- a/doc/workbook/generating_response/generating_response.md -+++ b/doc/workbook/generating_response/generating_response.md -@@ -1,5 +1,5 @@ - --Nav: [Workbook](../workbook.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md) | [Handling Cookies](/doc/workbook/handling_cookies/handling_cookies.md) -+Nav: [Workbook](../workbook.md) :: [Handling Requests: Header Fields](../handling_request/headers.md) :: [Handling Cookies](../handling_cookies/handling_cookies.md) - - - ## EWF Generating Response -@@ -14,7 +14,8 @@ Nav: [Workbook](../workbook.md) | [Handling Requests: Header Fields](/doc/workbo - - [Response Header Fields](#header_fields) - - -- -+ -+ - ## 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 don’t. For example, responses to HEAD requests should never include a document, and various status codes essentially indicate failure or redirection (and thus either don’t include a document or include only a short error-message document). - -- -+ -+ - ## 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/). - -- -+ -+ - ## 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. - -- -+ -+ - ## [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)```. - - -- -+ -+ - ### Example Staus Codes - Basic Service that builds a simple web page to show the most common status codes - ```eiffel -@@ -298,7 +303,8 @@ end - - - -- -+ -+ - ### 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 - - ``` - -- -+ -+ - ## [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) -diff --git a/doc/workbook/handling_cookies/handling_cookies.md b/doc/workbook/handling_cookies/handling_cookies.md -index f1de9bd..316ba48 100644 ---- a/doc/workbook/handling_cookies/handling_cookies.md -+++ b/doc/workbook/handling_cookies/handling_cookies.md -@@ -1,4 +1,4 @@ --Nav: [Workbook](../workbook.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md) -+Nav: [Workbook](../workbook.md) :: [Generating Responses](../generating_response/generating_response.md) - - # Handling Cookies - -@@ -9,9 +9,10 @@ Nav: [Workbook](../workbook.md) | [Generating Responses](/doc/workbook/generatin - - [How to read a cookie](#read_cookie) - - [Examples](#examples) - -- --## [Cookie](http://httpwg.github.io/specs/rfc6265.html) --A cookie is a piece of data that can be stored in a browser's cache. If you visit a web site and then revisit it, the cookie data can be used to identify you as a return visitor. Cookies enable state information, such as an online shopping cart, to be remembered. A cookie can be short term, holding data for a single web session, that is, until you close the browser, or a cookie can be longer term, holding data for a week or a year. -+ -+ -+## Cookie -+A [cookie](http://httpwg.github.io/specs/rfc6265.html) is a piece of data that can be stored in a browser's cache. If you visit a web site and then revisit it, the cookie data can be used to identify you as a return visitor. Cookies enable state information, such as an online shopping cart, to be remembered. A cookie can be short term, holding data for a single web session, that is, until you close the browser, or a cookie can be longer term, holding data for a week or a year. - - Cookies are used a lot in web client-server communication. - -@@ -30,7 +31,8 @@ Client send cookies to server - - - -- -+ -+ - ### Cookie properties - - - Comment: describe the purpose of the cookie. Note that server doesn’t receive this information when client sends cookie in request header. -@@ -43,7 +45,8 @@ Client send cookies to server - - HttpOnly: Checks whether this Cookie has been marked as HttpOnly. - - Version: - -- -+ -+ - ## 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. - - -- -+ -+ - ### 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 - ``` -- -+ -+ - ### How to read Cookies - - Reading a particular cookie -@@ -130,7 +135,8 @@ Reading all the cookies - ``` - - -- -+ -+ - ### 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) -diff --git a/doc/workbook/handling_request/form.md b/doc/workbook/handling_request/form.md -index c72772b..f5f7f33 100644 ---- a/doc/workbook/handling_request/form.md -+++ b/doc/workbook/handling_request/form.md -@@ -1,13 +1,11 @@ --Nav: [Workbook](../workbook.md) | [Basic Concepts] (/doc/workbook/basics/basics.md) | [Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md) -- -- --#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. - -- -+ -+ - ## Reading Form Data - EWF [WSF_REQUEST]() class, provides features to handling this form parsing automatically. - -- -+ -+ - ### 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'. -- -+ -+ - ### 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. - -- -+ -+ - ### 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 - - -- -+ -+ - ## 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 - - - ``` -- -+ -+ - ### 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 - ``` -- -+ -+ - ### 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 - ``` -- -+ -+ - ### 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. - -- -+ -+ - ### 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 - ``` - -- -+ -+ - ## 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 - -- -+ -+ - ## Upload Files - How can we read data when the date come from an uploaded file/s?. - HTML supports a form element ``` ``` to upload a single file and ``` ``` 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. - - -- -+ -+ - ## 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 and 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) -diff --git a/doc/workbook/handling_request/headers.md b/doc/workbook/handling_request/headers.md -index bba056e..5f0945f 100644 ---- a/doc/workbook/handling_request/headers.md -+++ b/doc/workbook/handling_request/headers.md -@@ -1,7 +1,7 @@ --Nav: [Workbook](../workbook.md) | [Handling Requests: Form/Query parameters] (/doc/workbook/handling_request/form.md) | [Generating Responses](/doc/workbook/generating_response/generating_response.md) -+Nav: [Workbook](../workbook.md) :: [Handling Requests: Form/Query parameters](./form.md) :: [Generating Responses](../generating_response/generating_response.md) - - --#Handling Requests: Headers -+# Handling Requests: Headers - - ##### Introduction - - 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`. - - -+ - ## 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). - - --####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 - - - -+ - #### 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). - - -+ - * [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]() - - -+ - * [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). - - -+ - * [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. - - -+ - * [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). - - -+ - * [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. - - -+ - * [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. - - -+ - * [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. - - -+ - * [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). - - -+ - * [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. - - -+ - * [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. - - -+ - * [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”). - - -+ - * [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. - - -+ - * [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. - - -+ - #### 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 - ``` - - -+ - #### 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) - -diff --git a/doc/workbook/readme.md b/doc/workbook/readme.md -index 6353245..5274bf8 100644 ---- a/doc/workbook/readme.md -+++ b/doc/workbook/readme.md -@@ -1,4 +1,4 @@ --The [Workbook](/doc/workbook.md) lets you discover the EiffelWeb framework. -+The [Workbook](./workbook.md) lets you discover the EiffelWeb framework. - --[Enter the documentation](/doc/workbook.md) -+[Enter the documentation](./workbook.md) - -diff --git a/doc/workbook/workbook.md b/doc/workbook/workbook.md -index 07ddc2f..c454c49 100644 ---- a/doc/workbook/workbook.md -+++ b/doc/workbook/workbook.md -@@ -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) - - -+ - # 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) - - - -+ - ## Introduction --[Basic Concepts] (/doc/workbook/basics/basics.md). -+[Basic Concepts](./basics/basics.md). - - -+ - ## 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). - - -+ - ## Handling Requests: Header Fields --[Handling Requests: Header Fields](/doc/workbook/handling_request/headers.md). -+[Handling Requests: Header Fields](./handling_request/headers.md). - - -+ - ## Generating Response --[Generating Responses](/doc/workbook/generating_response/generating_response.md) -+[Generating Responses](./generating_response/generating_response.md) - - -+ - ## Handling Cookies --[Handling Cookies](/doc/workbook/handling_cookies/handling_cookies.md) -+[Handling Cookies](./handling_cookies/handling_cookies.md) -+ -+ - -- - ## EWF Deployment --[EWF Deployment](/doc/workbook/deployment.md) -+[EWF Deployment](./deployment/readme.md) -diff --git a/examples/proxy/application.e b/examples/proxy/application.e -new file mode 100644 -index 0000000..a90f489 ---- /dev/null -+++ b/examples/proxy/application.e -@@ -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 -diff --git a/examples/proxy/application_execution.e b/examples/proxy/application_execution.e -new file mode 100644 -index 0000000..ab54495 ---- /dev/null -+++ b/examples/proxy/application_execution.e -@@ -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 -diff --git a/examples/proxy/proxy.ecf b/examples/proxy/proxy.ecf -new file mode 100644 -index 0000000..9bf59a5 ---- /dev/null -+++ b/examples/proxy/proxy.ecf -@@ -0,0 +1,28 @@ -+ -+ -+ -+ -+ /.svn$ -+ /CVS$ -+ /EIFGENs$ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/examples/proxy/server.ini b/examples/proxy/server.ini -new file mode 100644 -index 0000000..ae90215 ---- /dev/null -+++ b/examples/proxy/server.ini -@@ -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 -diff --git a/examples/simple/application.e b/examples/simple/application.e -index d1de21d..e86ee66 100644 ---- a/examples/simple/application.e -+++ b/examples/simple/application.e -@@ -20,9 +20,18 @@ 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) -+-- set_service_option ("socket_timeout", 50) -+-- set_service_option ("max_concurrent_connections", 100) -+-- set_service_option ("keep_alive_timeout", 15) -+-- set_service_option ("max_keep_alive_requests", 300) -+ -+ import_service_options (create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI}.make_from_file ("simple.ini")) -+ -+-- set_service_option ("socket_timeout", 5) -+-- set_service_option ("keep_alive_timeout", 3) - end - -- -- - end -diff --git a/examples/simple/application_execution.e b/examples/simple/application_execution.e -index b02bdf5..179f215 100644 ---- a/examples/simple/application_execution.e -+++ b/examples/simple/application_execution.e -@@ -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 -diff --git a/examples/simple/simple.ecf b/examples/simple/simple.ecf -index f341867..fb45586 100644 ---- a/examples/simple/simple.ecf -+++ b/examples/simple/simple.ecf -@@ -1,35 +1,28 @@ - -- -+ - - -- /EIFGENs$ -- /CVS$ - /.svn$ -+ /CVS$ -+ /EIFGENs$ - -- -+ - - - - - - -- -- -+ - - - -- -- -- -- -- -- - - - - - -+ -+ -+ - -diff --git a/examples/simple/simple.ini b/examples/simple/simple.ini -new file mode 100644 -index 0000000..ae90215 ---- /dev/null -+++ b/examples/simple/simple.ini -@@ -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 -diff --git a/examples/simple_ssl/application.e b/examples/simple_ssl/application.e -new file mode 100644 -index 0000000..e890c18 ---- /dev/null -+++ b/examples/simple_ssl/application.e -@@ -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 -diff --git a/examples/simple_ssl/application_execution.e b/examples/simple_ssl/application_execution.e -new file mode 100644 -index 0000000..2d6d0a7 ---- /dev/null -+++ b/examples/simple_ssl/application_execution.e -@@ -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 ("

This is a secured connection! (https)

%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 -diff --git a/examples/simple_ssl/simple.crt b/examples/simple_ssl/simple.crt -new file mode 100644 -index 0000000..6147c20 ---- /dev/null -+++ b/examples/simple_ssl/simple.crt -@@ -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----- -diff --git a/examples/simple_ssl/simple.ini b/examples/simple_ssl/simple.ini -new file mode 100644 -index 0000000..2ec39e1 ---- /dev/null -+++ b/examples/simple_ssl/simple.ini -@@ -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 -diff --git a/examples/simple_ssl/simple.key b/examples/simple_ssl/simple.key -new file mode 100644 -index 0000000..e5e22a5 ---- /dev/null -+++ b/examples/simple_ssl/simple.key -@@ -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----- -diff --git a/examples/simple_ssl/simple_ssl.ecf b/examples/simple_ssl/simple_ssl.ecf -new file mode 100644 -index 0000000..51e2b9a ---- /dev/null -+++ b/examples/simple_ssl/simple_ssl.ecf -@@ -0,0 +1,27 @@ -+ -+ -+ -+ Simple EiffelWeb standalone server with SSL support (Concurrent connection supported thanks to SCOOP). -+ -+ -+ /.svn$ -+ /CVS$ -+ /EIFGENs$ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Simple EiffelWeb standalone server with SSL support (Single threaded, thus no concurrent connection.) -+ -+ -+ -diff --git a/examples/upload_image/upload_image-safe.ecf b/examples/upload_image/upload_image-safe.ecf -index 0916cdc..b573ad5 100644 ---- a/examples/upload_image/upload_image-safe.ecf -+++ b/examples/upload_image/upload_image-safe.ecf -@@ -1,7 +1,6 @@ - - -- -- -+ - - /EIFGENs$ - /\.git$ -@@ -11,14 +10,26 @@ - - - -- -+ - -- - - - - - -+ -+ -+ -+ -+ - - -+ -+ -+ -+ -+ -+ -+ -+ - -diff --git a/examples/websocket/application.e b/examples/websocket/application.e -new file mode 100644 -index 0000000..72f4f62 ---- /dev/null -+++ b/examples/websocket/application.e -@@ -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 -diff --git a/examples/websocket/application_execution.e b/examples/websocket/application_execution.e -new file mode 100644 -index 0000000..92f82be ---- /dev/null -+++ b/examples/websocket/application_execution.e -@@ -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 ("

Websocket demo

") -+ 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 := "[ -+ -+ -+ -+ -+ -+ -+ -+WebSockets Client -+ -+ -+
-+
-+

WebSockets Client

-+
-+ -+ -+
-+
-+ -+ -+ ]" -+ Result.replace_substring_all ("##PORTNUMBER##", a_port.out) -+ end -+ -+ -+end -diff --git a/examples/websocket/websocket_app.ecf b/examples/websocket/websocket_app.ecf -new file mode 100644 -index 0000000..13f9527 ---- /dev/null -+++ b/examples/websocket/websocket_app.ecf -@@ -0,0 +1,21 @@ -+ -+ -+ -+ -+ -+ /.svn$ -+ /CVS$ -+ /EIFGENs$ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/examples/websocket/ws.ini b/examples/websocket/ws.ini -new file mode 100644 -index 0000000..b04bd03 ---- /dev/null -+++ b/examples/websocket/ws.ini -@@ -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 -diff --git a/library/network/protocol/http/src/http_header.e b/library/network/protocol/http/src/http_header.e -index db797f9..49dec76 100644 ---- a/library/network/protocol/http/src/http_header.e -+++ b/library/network/protocol/http/src/http_header.e -@@ -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 -diff --git a/library/security/openid/consumer/src/openid_consumer.e b/library/security/openid/consumer/src/openid_consumer.e -index 68b73a5..95123a5 100644 ---- a/library/security/openid/consumer/src/openid_consumer.e -+++ b/library/security/openid/consumer/src/openid_consumer.e -@@ -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) -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/none/httpd_connection_handler.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/none/httpd_connection_handler.e -new file mode 100644 -index 0000000..5bc857c ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/none/httpd_connection_handler.e -@@ -0,0 +1,86 @@ -+note -+ description: "[ -+ Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: none -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ HTTPD_CONNECTION_HANDLER -+ -+inherit -+ HTTPD_CONNECTION_HANDLER_I -+ -+create -+ make -+ -+feature {NONE} -- Initialization -+ -+ initialize -+ do -+ end -+ -+feature -- Access -+ -+ is_shutdown_requested: BOOLEAN -+ -- -+ -+ shutdown_requested (a_server: like server): BOOLEAN -+ do -+ -- FIXME: we should probably remove this possibility, check with EWF if this is needed. -+ Result := a_server.controller.shutdown_requested -+ end -+ -+feature {HTTPD_SERVER_I} -- Execution -+ -+ accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET) -+ local -+ cl: HTTPD_STREAM_SOCKET -+ do -+ is_shutdown_requested := is_shutdown_requested or shutdown_requested (server) -+ if is_shutdown_requested then -+ -- Cancel -+ elseif attached factory.new_handler as h then -+ cl := h.client_socket -+ a_listening_socket.accept_to (cl) -+ if h.is_connected then -+ h.safe_execute -+ end -+ else -+ check is_not_full: False end -+ end -+ update_is_shutdown_requested -+ end -+ -+ update_is_shutdown_requested -+ do -+ is_shutdown_requested := shutdown_requested (server) -+ end -+ -+ shutdown -+ do -+ if not is_shutdown_requested then -+ is_shutdown_requested := True -+ server.controller.shutdown -+ end -+ end -+ -+feature {HTTPD_SERVER_I} -- Status report -+ -+ wait_for_completion -+ -- Wait until Current is ready for shutdown -+ do -+ -- no concurrency, then current task should be done. -+ end -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/none/httpd_request_handler.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/none/httpd_request_handler.e -new file mode 100644 -index 0000000..c033de7 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/none/httpd_request_handler.e -@@ -0,0 +1,32 @@ -+note -+ description : "Concurrent specific feature to implement HTTPD_REQUEST_HANDLER" -+ date : "$Date$" -+ revision : "$Revision$" -+ -+deferred class -+ HTTPD_REQUEST_HANDLER -+ -+inherit -+ HTTPD_REQUEST_HANDLER_I -+ redefine -+ is_persistent_connection_supported -+ end -+ -+feature -- Status report -+ -+ is_persistent_connection_supported: BOOLEAN = False -+ -- -+ -- When there is no concurrency support, do not try to support -+ -- persistent connection! -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/none/httpd_request_handler_factory.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/none/httpd_request_handler_factory.e -new file mode 100644 -index 0000000..1c93e9e ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/none/httpd_request_handler_factory.e -@@ -0,0 +1,15 @@ -+note -+ description: "Implementation of request handler factory for concurrency mode: none" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ HTTPD_REQUEST_HANDLER_FACTORY -+ -+inherit -+ HTTPD_REQUEST_HANDLER_FACTORY_I -+ -+note -+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others" -+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" -+end -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_connection_handler.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_connection_handler.e -new file mode 100644 -index 0000000..3941b86 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_connection_handler.e -@@ -0,0 +1,146 @@ -+note -+ description: "[ -+ Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: SCOOP -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ HTTPD_CONNECTION_HANDLER -+ -+inherit -+ HTTPD_CONNECTION_HANDLER_I -+ redefine -+ initialize -+ end -+ -+create -+ make -+ -+feature {NONE} -- Initialization -+ -+ initialize -+ local -+ n: INTEGER -+ p: like pool -+ do -+ n := max_concurrent_connections (server).max (1) -- At least one processor! -+ create p.make (n) -+ initialize_pool (p, n) -+ pool := p -+ end -+ -+ initialize_pool (p: like pool; n: INTEGER) -+ -- Initialize Concurrent pool of `n' potential separate connection handlers. -+ do -+ p.set_count (n) -+ end -+ -+feature -- Access -+ -+ is_shutdown_requested: BOOLEAN -+ -- -+ -+ max_concurrent_connections (a_server: like server): INTEGER -+ -- Max concurrent connection settings from server `a_server'. -+ do -+ Result := a_server.configuration.max_concurrent_connections -+ end -+ -+feature {HTTPD_SERVER_I} -- Execution -+ -+ shutdown -+ -- -+ do -+ if not is_shutdown_requested then -+ is_shutdown_requested := True -+ pool_gracefull_stop (pool) -+ end -+ end -+ -+ pool_gracefull_stop (p: like pool) -+ -- Graceful stop concurrent pool of separate connection handlers. -+ do -+ p.gracefull_stop -+ end -+ -+ accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET) -+ -- -+ do -+ accept_connection_on_pool (pool, a_listening_socket) -- Wait on not pool.is_full or is_stop_requested -+ end -+ -+ accept_connection_on_pool (a_pool: like pool; a_listening_socket: HTTPD_STREAM_SOCKET) -+ -- Process accept connection -+ -- note that the precondition matters for scoop synchronization. -+ require -+ concurrency: not a_pool.is_full or is_shutdown_requested or a_pool.stop_requested -+ local -+ cl: separate HTTPD_STREAM_SOCKET -+ do -+ debug ("dbglog") -+ dbglog (generator + ".ENTER accept_connection_on_pool") -+ end -+ if is_shutdown_requested then -+ -- Cancel -+ elseif attached a_pool.separate_item (factory) as h then -+ cl := separate_client_socket (h) -+ a_listening_socket.accept_to (cl) -+ process_handler (h) -+ else -+ check is_not_full: False end -+ end -+ debug ("dbglog") -+ dbglog (generator + ".LEAVE accept_connection_on_pool") -+ end -+ end -+ -+ process_handler (hdl: separate HTTPD_REQUEST_HANDLER) -+ -- Process request handler `hdl' as soon as `hdl' is connected to accepted socket. -+ require -+ hdl.is_connected -+ do -+ hdl.safe_execute -+ end -+ -+feature {HTTPD_SERVER_I} -- Status report -+ -+ wait_for_completion -+ -- Wait until Current is ready for shutdown. -+ do -+ wait_for_pool_completion (pool) -+ end -+ -+ wait_for_pool_completion (p: like pool) -+ -- Wait until concurrent pool is empty and terminated. -+ require -+ p.is_empty -- SCOOP wait condition. -+ do -+ p.terminate -+ end -+ -+feature {NONE} -- Implementation -+ -+ separate_client_socket (hdl: separate HTTPD_REQUEST_HANDLER): separate HTTPD_STREAM_SOCKET -+ -- Client socket for request handler `hdl'. -+ do -+ Result := hdl.client_socket -+ end -+ -+ pool: separate CONCURRENT_POOL [HTTPD_REQUEST_HANDLER] -+ -- Pool of separate connection handlers. -+ -+invariant -+ pool_attached: pool /= Void -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_request_handler.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_request_handler.e -new file mode 100644 -index 0000000..2defb09 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_request_handler.e -@@ -0,0 +1,62 @@ -+note -+ description: "[ -+ Instance of HTTPD_REQUEST_HANDLER will process the incoming connection -+ and extract information on the request and the server -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ HTTPD_REQUEST_HANDLER -+ -+inherit -+ HTTPD_REQUEST_HANDLER_I -+ redefine -+ release -+ end -+ -+ CONCURRENT_POOL_ITEM -+ rename -+ release as release_pool_item -+ end -+ -+feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation -+ -+ release -+ -- -+ local -+ d: detachable STRING -+ do -+ 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") -+ if d /= Void then -+ dbglog (generator + ".release: LEAVE {" + d + "}") -+ else -+ dbglog (generator + ".release: LEAVE {N/A}") -+ end -+ end -+ end -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_request_handler_factory.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_request_handler_factory.e -new file mode 100644 -index 0000000..e48a96a ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/httpd_request_handler_factory.e -@@ -0,0 +1,27 @@ -+note -+ description: "Implementation of request handler factory for concurrency mode: SCOOP" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ HTTPD_REQUEST_HANDLER_FACTORY -+ -+inherit -+ HTTPD_REQUEST_HANDLER_FACTORY_I -+ -+ CONCURRENT_POOL_FACTORY [HTTPD_REQUEST_HANDLER] -+ rename -+ new_separate_item as new_handler -+ end -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/pool/concurrent_pool.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/pool/concurrent_pool.e -new file mode 100644 -index 0000000..070f271 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/pool/concurrent_pool.e -@@ -0,0 +1,190 @@ -+note -+ description: "Concurrent pool for SCOOP concurrency mode." -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ CONCURRENT_POOL [G -> CONCURRENT_POOL_ITEM] -+ -+inherit -+ HTTPD_DEBUG_FACILITIES -+ -+create -+ make -+ -+feature {NONE} -- Initialization -+ -+ make (n: INTEGER) -+ do -+ capacity := n -+ create items.make_empty (n) -+ create busy_items.make_empty (n) -+ end -+ -+feature -- Access -+ -+ count: INTEGER -+ -- Number of concurrent items managed by Current pool. -+ -+ capacity: INTEGER -+ -- Maximum number of concurrent items managed by Current pool. -+ -+feature -- Status report -+ -+ is_full: BOOLEAN -+ -- Pool is full? -+ do -+ Result := count >= capacity -+ end -+ -+ is_empty: BOOLEAN -+ -- No concurrent item waiting in current pool. -+ do -+ Result := count = 0 -+ end -+ -+ stop_requested: BOOLEAN -+ -- Current pool received a request to terminate. -+ -+feature -- Access -+ -+ separate_item (a_factory: separate CONCURRENT_POOL_FACTORY [G]): detachable separate G -+ -- Reused, or new separate item of type {G} created by `a_factory'. -+ require -+ is_not_full: not is_full -+ local -+ i,n,pos: INTEGER -+ lst: like busy_items -+ l_item: detachable separate G -+ do -+ if not stop_requested then -+ from -+ lst := busy_items -+ pos := -1 -+ i := 0 -+ n := lst.count - 1 -+ until -+ i > n or l_item /= Void or pos >= 0 -+ loop -+ if not lst [i] then -- is free (i.e not busy) -+ pos := i -+ -+ if items.valid_index (pos) then -+ l_item := items [pos] -+ if l_item /= Void then -+ busy_items [pos] := True -+ end -+ end -+ if l_item = Void then -+ -- Empty, then let's create one. -+ l_item := a_factory.new_separate_item -+ register_item (l_item) -+ items [pos] := l_item -+ end -+ end -+ i := i + 1 -+ end -+ if l_item = Void then -+ -- Pool is FULL ... -+ check overcapacity: False end -+ else -+ debug ("pool", "dbglog") -+ dbglog ("Lock pool item #" + pos.out + " (free:"+ (capacity - count).out +"))") -+ end -+ count := count + 1 -+ busy_items [pos] := True -+ Result := l_item -+ a_factory.update_item (l_item) -+ end -+ end -+ end -+ -+feature -- Basic operation -+ -+ gracefull_stop -+ -- Request the Current pool to terminate. -+ do -+ stop_requested := True -+ end -+ -+feature {NONE} -- Internal -+ -+ items: SPECIAL [detachable separate G] -+ -- List of concurrent items. -+ -+ busy_items: SPECIAL [BOOLEAN] -+ -- Map of items being proceed. -+ -+feature {CONCURRENT_POOL_ITEM} -- Change -+ -+ release_item (a_item: separate G) -+ -- Unregister `a_item' from Current pool. -+ require -+ count > 0 -+ local -+ i,n,pos: INTEGER -+ lst: like items -+ do -+ -- release handler for reuse -+ from -+ lst := items -+ i := 0 -+ n := lst.count - 1 -+ until -+ i > n or lst [i] = a_item -+ loop -+ i := i + 1 -+ end -+ if i <= n then -+ pos := i -+ busy_items [pos] := False -+ count := count - 1 -+--reuse items [pos] := Void -+ debug ("pool", "dbglog") -+ dbglog ("Released pool item #" + i.out + " (free:"+ (capacity - count).out +"))") -+ end -+ else -+ check known_item: False end -+ end -+ end -+ -+feature -- Change -+ -+ set_count (n: INTEGER) -+ -- Set capacity of Current pool to `n'. -+ local -+ g: detachable separate G -+ do -+ capacity := n -+ items.fill_with (g, 0, n - 1) -+ busy_items.fill_with (False, 0, n - 1) -+ end -+ -+ terminate -+ -- Terminate current pool. -+ local -+ l_items: like items -+ do -+ l_items := items -+ l_items.wipe_out -+ end -+ -+feature {NONE} -- Implementation -+ -+ register_item (a_item: separate G) -+ -- Adopt `a_item' in current pool. -+ do -+ a_item.set_pool (Current) -+ end -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/pool/concurrent_pool_factory.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/pool/concurrent_pool_factory.e -new file mode 100644 -index 0000000..92e0f2c ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/pool/concurrent_pool_factory.e -@@ -0,0 +1,31 @@ -+note -+ description: "Factory in charge of creating new concurrent pool item." -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ CONCURRENT_POOL_FACTORY [G -> CONCURRENT_POOL_ITEM] -+ -+feature -- Access -+ -+ update_item (a_item: separate G) -+ -- Update `a_item' for optionally purpose. -+ do -+ end -+ -+ new_separate_item: separate G -+ -- New separated object of type {G}. -+ deferred -+ end -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/pool/concurrent_pool_item.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/pool/concurrent_pool_item.e -new file mode 100644 -index 0000000..2b5d1c6 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/scoop/pool/concurrent_pool_item.e -@@ -0,0 +1,52 @@ -+note -+ description: "[ -+ Item create by the CONCURRENT_POOL_FACTORY, and managed by the CONCURRENT_POOL -+ for SCOOP concurrency mode. -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ CONCURRENT_POOL_ITEM -+ -+feature {NONE} -- Access -+ -+ pool: detachable separate CONCURRENT_POOL [CONCURRENT_POOL_ITEM] -+ -- Associated concurrent pool component. -+ -+feature {CONCURRENT_POOL} -- Change -+ -+ set_pool (p: like pool) -+ -- Set associated `pool' to `p'. -+ do -+ pool := p -+ end -+ -+feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation -+ -+ release -+ -- Release Current pool item from associated pool. -+ do -+ if attached pool as p then -+ pool_release (p) -+ end -+ end -+ -+feature {NONE} -- Implementation -+ -+ pool_release (p: separate CONCURRENT_POOL [CONCURRENT_POOL_ITEM]) -+ do -+ p.release_item (Current) -+ end -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_connection_handler.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_connection_handler.e -new file mode 100644 -index 0000000..75115d3 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_connection_handler.e -@@ -0,0 +1,103 @@ -+note -+ description: "[ -+ Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: Thread -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ HTTPD_CONNECTION_HANDLER -+ -+inherit -+ HTTPD_CONNECTION_HANDLER_I -+ redefine -+ initialize -+ end -+ -+create -+ make -+ -+feature {NONE} -- Initialization -+ -+ initialize -+ local -+ n: INTEGER -+ do -+ n := max_concurrent_connections (server).max (1) -- At least one thread! -+ create pool.make (n.to_natural_32) -+ end -+ -+feature -- Access -+ -+ is_shutdown_requested: BOOLEAN -+ -+ max_concurrent_connections (a_server: like server): INTEGER -+ do -+ Result := a_server.configuration.max_concurrent_connections -+ end -+ -+feature {HTTPD_SERVER_I} -- Execution -+ -+ shutdown -+ do -+ if not is_shutdown_requested then -+ is_shutdown_requested := True -+ pool_gracefull_stop (pool) -+ end -+ end -+ -+ pool_gracefull_stop (p: like pool) -+ do -+ p.terminate -+ end -+ -+ accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET) -+ local -+ cl: separate HTTPD_STREAM_SOCKET -+ do -+ debug ("dbglog") -+ dbglog (generator + ".ENTER accept_connection {"+ a_listening_socket.descriptor.out +"}") -+ end -+ -+ if is_shutdown_requested then -+ -- cancel -+ elseif attached factory.new_handler as h then -+ cl := h.client_socket -+ a_listening_socket.accept_to (cl) -+ if h.is_connected then -+ pool.add_work (agent h.safe_execute) -+ end -+ end -+ -+ debug ("dbglog") -+ dbglog (generator + ".LEAVE accept_incoming_connection {"+ a_listening_socket.descriptor.out +"}") -+ end -+ end -+ -+feature {HTTPD_SERVER_I} -- Status report -+ -+ wait_for_completion -+ -- Wait until Current is ready for shutdown -+ do -+ pool.wait_for_completion -+ end -+ -+feature {NONE} -- Access -+ -+ pool: THREAD_POOL [HTTPD_REQUEST_HANDLER] --ANY] --POOLED_THREAD [HTTP_REQUEST_HANDLER]] -+ -- Pool of concurrent connection handlers. -+ -+invariant -+ pool_attached: pool /= Void -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_request_handler.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_request_handler.e -new file mode 100644 -index 0000000..57c6ecd ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_request_handler.e -@@ -0,0 +1,56 @@ -+note -+ description: "[ -+ Instance of HTTPD_REQUEST_HANDLER will process the incoming connection -+ and extract information on the request and the server -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ HTTPD_REQUEST_HANDLER -+ -+inherit -+ HTTPD_REQUEST_HANDLER_I -+ redefine -+ release -+ end -+ -+feature {HTTPD_CONNECTION_HANDLER_I} -- Basic operation -+ -+ release -+ -- -+ local -+ d: detachable STRING -+ do -+ 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") -+ if d /= Void then -+ dbglog (generator + ".release: LEAVE {" + d + "}") -+ else -+ dbglog (generator + ".release: LEAVE {N/A}") -+ end -+ end -+ end -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_request_handler_factory.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_request_handler_factory.e -new file mode 100644 -index 0000000..cf692e5 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/httpd_request_handler_factory.e -@@ -0,0 +1,15 @@ -+note -+ description: "Implementation of request handler factory for concurrency mode: Thread" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ HTTPD_REQUEST_HANDLER_FACTORY -+ -+inherit -+ HTTPD_REQUEST_HANDLER_FACTORY_I -+ -+note -+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others" -+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" -+end -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/pool/pooled_thread.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/pool/pooled_thread.e -new file mode 100644 -index 0000000..393e028 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/pool/pooled_thread.e -@@ -0,0 +1,121 @@ -+note -+ description: "{POOLED_THREAD} is used in combination with {THREAD_POOL} to allow for pooled threads." -+ legal: "See notice at end of class." -+ status: "Community Preview 1.0" -+ date: "$Date: 2009-09-01 19:15:37 -0300 (mar 01 de sep de 2009) $" -+ revision: "$Revision: 80577 $" -+ -+class -+ POOLED_THREAD [G] -+ -+inherit -+ THREAD -+ rename -+ make as thread_make -+ end -+ -+create {THREAD_POOL} -+ make -+ -+feature {NONE} -- Initialization -+ -+ make (a_thread_pool: THREAD_POOL [G]; a_semaphore: SEMAPHORE) -+ -- `a_thread_pool', the pool in which this thread is managed -+ -- `a_semaphore' is used for execution suspending -+ do -+ thread_make -+ thread_pool := a_thread_pool -+ semaphore := a_semaphore -+ end -+ -+feature {NONE} -- Access -+ -+ thread_pool: THREAD_POOL [G] -+ -- Pool manager in which this thread is pooled -+ -+ target: detachable G -+ -- Target on which the `thread_procedure' should be applied -+ -- Depending on which launch is used, target is not used -+ -+ thread_procedure: detachable PROCEDURE -+ -- Work that should be executed by the thread -+ -+ semaphore: SEMAPHORE -+ -- Semaphore share with all threads in a thread pool -+ -- to suspend execution until more work is available -+ -+feature -- Access -+ -+ set_target (a_target: G) -+ -- Sets the target on which the work should be executed -+ do -+ target := a_target -+ end -+ -+feature {NONE} -- Implementation -+ -+ execute -+ -- -+ local -+ done: BOOLEAN -+ do -+ from -+ semaphore.wait -+ thread_procedure := thread_pool.get_work (Current) -+ until -+ done -+ loop -+ if attached thread_procedure as l_work then -+ if attached target as t then -+ l_work.call ([t]) -+ else -+ l_work.call (Void) -+ end -+ end -+ if thread_pool.over then -+ done := True -+ else -+ thread_procedure := thread_pool.get_work (Current) -+ if thread_procedure = Void then -+ semaphore.wait -+ thread_procedure := thread_pool.get_work (Current) -+ end -+ end -+ end -+ thread_pool.thread_terminated (Current) -+ end -+ -+note -+ copyright: "2011-2012, Javier Velilla and others" -+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" -+ licensing_options: "http://www.eiffel.com/licensing" -+ copying: "[ -+ This file is part of Eiffel Software's Eiffel Development Environment. -+ -+ Eiffel Software's Eiffel Development Environment is free -+ software; you can redistribute it and/or modify it under -+ the terms of the GNU General Public License as published -+ by the Free Software Foundation, version 2 of the License -+ (available at the URL listed under "license" above). -+ -+ Eiffel Software's Eiffel Development Environment is -+ distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty -+ of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -+ See the GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public -+ License along with Eiffel Software's Eiffel Development -+ Environment; if not, write to the Free Software Foundation, -+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ ]" -+ 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 -+ -+ -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/pool/thread_pool.e b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/pool/thread_pool.e -new file mode 100644 -index 0000000..02e94d9 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/concurrency/thread/pool/thread_pool.e -@@ -0,0 +1,228 @@ -+note -+ description: "[ -+ A thread pool manager. Manages threads up to `capacity' and queue after that, -+ till threads get available again. -+ ]" -+ legal: "See notice at end of class." -+ status: "Community Preview 1.0" -+ date: "$Date: 2009-09-01 19:15:37 -0300 (mar 01 de sep de 2009) $" -+ revision: "$Revision: 80577 $" -+ -+class -+ THREAD_POOL [G] -+ -+inherit -+ EXECUTION_ENVIRONMENT -+ -+create -+ make -+ -+feature {NONE} -- Initialization -+ -+ make (n: like capacity) -+ -- Initialize current pool with capacity `n'. -+ require -+ n_positive: n > 0 -+ n_not_too_large: n < {INTEGER_32}.max_value.as_natural_32 -+ local -+ i: NATURAL -+ do -+ capacity := n -+ create work_queue.make (n.to_integer_32) -+ create work_queue_mutex.make -+ create over_mutex.make -+ create termination_mutex.make -+ create work_semaphore.make (capacity.as_integer_32) -+ from -+ i := 1 -+ until -+ i > capacity -+ loop -+ work_semaphore.wait -+ i := i + 1 -+ end -+ initialize_threads -+ terminated_count := capacity -+ is_over := False -+ ensure -+ capacity_set: capacity = n -+ work_queue_set: work_queue.is_empty -+ end -+ -+ initialize_threads -+ -- Launches all threads -+ local -+ i: NATURAL -+ thread: POOLED_THREAD [G] -+ do -+ from -+ i := 1 -+ until -+ i > capacity -+ loop -+ create thread.make (Current, work_semaphore) -+ thread.launch -+ i := i + 1 -+ end -+ end -+ -+feature -- Access -+ -+ capacity: NATURAL -+ -- Maximal number of threads allowed (queuing otherwise) -+ -+ queue_count: NATURAL -+ -- Number of items in queue -+ do -+ work_queue_mutex.lock -+ Result := work_queue.count.as_natural_32 -+ work_queue_mutex.unlock -+ end -+ -+feature -- Status report -+ -+ valid_action (a_action: PROCEDURE): BOOLEAN -+ -- Is `a_action' a valid action for the current pool. -+ do -+ -- There should be no open operands. -+ Result := a_action.valid_operands (Void) -+ end -+ -+feature -- Basic operations -+ -+ add_work (work: PROCEDURE) -+ -- Launches a thread with the specified argument `arg'. Reuse of thread if possible. -+ require -+ valid_action: valid_action (work) -+ do -+ work_queue_mutex.lock -+ work_queue.extend (work) -+ if work_queue.count <= capacity.as_integer_32 then -+ -- Let one thread wake up and do the work -+ work_semaphore.post -+ end -+ work_queue_mutex.unlock -+ end -+ -+ over: BOOLEAN -+ -- Is the thread pool being terminated? -+ do -+ over_mutex.lock -+ Result := is_over -+ over_mutex.unlock -+ end -+ -+ thread_terminated (a_thread: POOLED_THREAD [G]) -+ -- Notifies the thread pool that a thread has terminated its execution. -+ do -+ termination_mutex.lock -+ terminated_count := terminated_count - 1 -+ termination_mutex.unlock -+ end -+ -+ get_work (requester: POOLED_THREAD [G]): detachable PROCEDURE -+ -- If there is work to do, it is returned -+ -- Yields Void otherwise -+ do -+ if not over then -+ work_queue_mutex.lock -+ if not work_queue.is_empty then -+ Result := work_queue.item -+ work_queue.remove -+ end -+ work_queue_mutex.unlock -+ end -+ end -+ -+ wait_for_completion -+ -- Wait until there is no more work to be completed -+ local -+ done: BOOLEAN -+ do -+ from -+ -+ until -+ done -+ loop -+ work_queue_mutex.lock -+ done := work_queue.is_empty -+ work_queue_mutex.unlock -+ if not done then -+ sleep (1) -+ end -+ end -+ end -+ -+ terminate -+ -- Terminates all the threads after their execution -+ do -+ over_mutex.lock -+ is_over := True -+ over_mutex.unlock -+ from -+ termination_mutex.lock -+ until -+ terminated_count = 0 -+ loop -+ work_semaphore.post -+ termination_mutex.unlock -+ termination_mutex.lock -+ end -+ termination_mutex.unlock -+ end -+ -+feature {NONE} -- Implementation: Access -+ -+ work_queue: ARRAYED_QUEUE [PROCEDURE] -+ -- Queue that holds unprocessed requests as agents -+ -- Thread-safe access when accessor holds `queue_mutex' -+ -+ work_queue_mutex: MUTEX -+ -- Mutex for the queue -+ -+ work_semaphore: SEMAPHORE -+ -- Semaphore which hols the number of work to be done. -+ -- Needed to wake up worker threads -+ -+ terminated_count: NATURAL -+ -- -+ -+ is_over: BOOLEAN -+ -- Is the thread pool being terminated? -+ -+ over_mutex: MUTEX -+ -- Mutex for the `is_over' variable -+ -+ termination_mutex: MUTEX -+;note -+ copyright: "2011-2012, Javier Velilla, Jocelyn Fiat and others" -+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" -+ licensing_options: "http://www.eiffel.com/licensing" -+ copying: "[ -+ This file is part of Eiffel Software's Eiffel Development Environment. -+ -+ Eiffel Software's Eiffel Development Environment is free -+ software; you can redistribute it and/or modify it under -+ the terms of the GNU General Public License as published -+ by the Free Software Foundation, version 2 of the License -+ (available at the URL listed under "license" above). -+ -+ Eiffel Software's Eiffel Development Environment is -+ distributed in the hope that it will be useful, but -+ WITHOUT ANY WARRANTY; without even the implied warranty -+ of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -+ See the GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public -+ License along with Eiffel Software's Eiffel Development -+ Environment; if not, write to the Free Software Foundation, -+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ ]" -+ 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_configuration_i.e b/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_configuration_i.e -new file mode 100644 -index 0000000..7c06b59 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_configuration_i.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_constants.e b/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_constants.e -new file mode 100644 -index 0000000..71e4dcc ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_constants.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_request_settings.e b/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_request_settings.e -new file mode 100644 -index 0000000..a591cac ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/configuration/httpd_request_settings.e -@@ -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 -+ -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/http_network-safe.ecf b/library/server/ewsgi/connectors/standalone/lib/httpd/http_network-safe.ecf -new file mode 100644 -index 0000000..faea6dd ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/http_network-safe.ecf -@@ -0,0 +1,38 @@ -+ -+ -+ -+ -+ -+ /.git$ -+ /.svn$ -+ /EIFGENs$ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/http_network.ecf b/library/server/ewsgi/connectors/standalone/lib/httpd/http_network.ecf -new file mode 100644 -index 0000000..25cc31e ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/http_network.ecf -@@ -0,0 +1,39 @@ -+ -+ -+ -+ -+ -+ /.git$ -+ /.svn$ -+ /EIFGENs$ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd-safe.ecf b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd-safe.ecf -new file mode 100644 -index 0000000..d25947d ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd-safe.ecf -@@ -0,0 +1,78 @@ -+ -+ -+ -+ -+ -+ /.git$ -+ /.svn$ -+ /EIFGENs$ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ /concurrency$ -+ /no_ssl$ -+ /ssl$ -+ /network$ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd.ecf b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd.ecf -new file mode 100644 -index 0000000..9d62c60 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd.ecf -@@ -0,0 +1,77 @@ -+ -+ -+ -+ -+ -+ /.git$ -+ /.svn$ -+ /EIFGENs$ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ /concurrency$ -+ /no_ssl$ -+ /ssl$ -+ /network$ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_connection_handler_i.e b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_connection_handler_i.e -new file mode 100644 -index 0000000..be3e51f ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_connection_handler_i.e -@@ -0,0 +1,97 @@ -+note -+ description: "[ -+ Interface for the incoming connection handler. -+ -+ Each incoming socket connection is processed by -+ an implementation of HTTPD_CONNECTION_HANDLER_I. -+ -+ Note there are 3 implementations, one for each concurrent mode: none, thread, scoop. -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ HTTPD_CONNECTION_HANDLER_I -+ -+inherit -+ HTTPD_DEBUG_FACILITIES -+ -+feature {NONE} -- Initialization -+ -+ frozen make (a_server: like server) -+ do -+ server := a_server -+ factory := separate_factory (a_server) -+ initialize -+ end -+ -+ initialize -+ deferred -+ end -+ -+feature {NONE} -- Access -+ -+ factory: separate HTTPD_REQUEST_HANDLER_FACTORY -+ -- Request handler factory. -+ -+ server: separate HTTPD_SERVER_I -+ -- Associated server. -+ -+feature {HTTPD_SERVER_I} -- Execution -+ -+ accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET) -+ -- Accept incoming connection from `a_listening_socket'. -+ deferred -+ end -+ -+ shutdown -+ -- Shutdown server. -+ deferred -+ end -+ -+ wait_for_completion -+ -- Wait until Current completed any pending task. -+ --| Used for SCOOP synchronisation. -+ deferred -+ end -+ -+feature {HTTPD_SERVER} -- Status report -+ -+ is_shutdown_requested: BOOLEAN -+ -- Any request to shutdown the server? -+ deferred -+ end -+ -+feature {NONE} -- Implementation -+ -+ log (a_message: separate READABLE_STRING_8) -+ -- Log `a_message' -+ do -+ -- FIXME: Concurrency issue on `server' -+ separate_server_log (server, a_message) -+ end -+ -+ separate_factory (a_server: like server): like factory -+ -- Separate factory from `a_server'. -+ --| required by SCOOP design. -+ do -+ Result := a_server.factory -+ end -+ -+ separate_server_log (a_server: like server; a_message: separate READABLE_STRING_8) -+ -- Concurrent call to `a_server.log (a_message)'. -+ do -+ a_server.log (a_message) -+ end -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_controller.e b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_controller.e -new file mode 100644 -index 0000000..f9a6667 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_controller.e -@@ -0,0 +1,28 @@ -+note -+ description: "[ -+ Object used to control (i.e shutdown) the server. -+ Mostly needed in SCOOP concurrency mode. -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ HTTPD_CONTROLLER -+ -+feature -- Operation -+ -+ shutdown -+ -- Request the associated server to be shutdown. -+ do -+ shutdown_requested := True -+ end -+ -+feature -- Status report. -+ -+ shutdown_requested: BOOLEAN -+ -- Shutdown requested. -+ -+;note -+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others" -+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" -+end -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_debug_facilities.e b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_debug_facilities.e -new file mode 100644 -index 0000000..3182332 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_debug_facilities.e -@@ -0,0 +1,50 @@ -+note -+ description: " Routines used for debug logging." -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ HTTPD_DEBUG_FACILITIES -+ -+feature {NONE} -- Output -+ -+ dbglog (m: READABLE_STRING_8) -+ require -+ not m.ends_with_general ("%N") -+ local -+ s: STRING -+ do -+ debug ("dbglog") -+ create s.make (24) -+ s.append ("[EWF/DBG] <#") -+ s.append_integer (processor_id_from_object (Current)) -+ s.append ("> ") -+ s.append (generator) -+ s.append (create {STRING}.make_filled (' ', (46 - s.count).max (0))) -+ s.append (" | ") -+ s.append (m) -+ s.append ("%N") -+ print (s) -+ end -+ end -+ -+feature -- runtime -+ -+ frozen processor_id_from_object (a_object: separate ANY): INTEGER_32 -+ external -+ "C inline use %"eif_scoop.h%"" -+ alias -+ "RTS_PID(eif_access($a_object))" -+ end -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_logger.e b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_logger.e -new file mode 100644 -index 0000000..057f43a ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_logger.e -@@ -0,0 +1,26 @@ -+note -+ description: "Logging facilities component" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ HTTPD_LOGGER -+ -+feature -- Logs -+ -+ log (a_message: separate READABLE_STRING_8) -+ -- Log `a_message' -+ 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_logger_constants.e b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_logger_constants.e -new file mode 100644 -index 0000000..c75bec4 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_logger_constants.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_request_handler_factory_i.e b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_request_handler_factory_i.e -new file mode 100644 -index 0000000..940d7a0 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_request_handler_factory_i.e -@@ -0,0 +1,26 @@ -+note -+ description: "Summary description for {HTTPD_REQUEST_HANDLER_FACTORY_I}." -+ author: "" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ HTTPD_REQUEST_HANDLER_FACTORY_I -+ -+feature -- Factory -+ -+ new_handler: separate HTTPD_REQUEST_HANDLER -+ 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_request_handler_i.e b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_request_handler_i.e -new file mode 100644 -index 0000000..53ce713 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_request_handler_i.e -@@ -0,0 +1,527 @@ -+note -+ description: "HTTPD handler interface processing request." -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ HTTPD_REQUEST_HANDLER_I -+ -+inherit -+ HTTPD_DEBUG_FACILITIES -+ -+ HTTPD_LOGGER_CONSTANTS -+ -+ HTTPD_SOCKET_FACTORY -+ -+feature {NONE} -- Initialization -+ -+ 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 -+ do -+ reset_request -+ -+ has_error := False -+ if attached internal_client_socket as l_sock then -+ l_sock.cleanup -+ end -+ internal_client_socket := Void -+ end -+ -+ reset_request -+ do -+ version := Void -+ remote_info := Void -+ -+ -- FIXME: optimize to just wipe_out if needed -+ create method.make_empty -+ create uri.make_empty -+ create request_header.make_empty -+ create request_header_map.make (10) -+ -+ is_persistent_connection_requested := False -+ end -+ -+feature -- Status report -+ -+ is_connected: BOOLEAN -+ -- Is handler connected to incoming request via `client_socket'? -+ do -+ Result := client_socket.descriptor_available -+ end -+ -+feature -- Access -+ -+ internal_client_socket: detachable HTTPD_STREAM_SOCKET -+ -+ client_socket: HTTPD_STREAM_SOCKET -+ local -+ s: like internal_client_socket -+ do -+ s := internal_client_socket -+ if s = Void then -+ s := new_client_socket (is_secure) -+ internal_client_socket := s -+ end -+ Result := s -+ end -+ -+ request_header: STRING -+ -- Header' source -+ -+ request_header_map: HASH_TABLE [STRING, STRING] -+ -- Contains key:value of the header -+ -+ method: STRING -+ -- http verb -+ -+ uri: STRING -+ -- http endpoint -+ -+ version: detachable STRING -+ -- http_version -+ --| unused for now -+ -+ remote_info: detachable TUPLE [addr: STRING; hostname: STRING; port: INTEGER] -+ -- Information related to remote client -+ -+ is_persistent_connection_requested: BOOLEAN -+ -- Persistent connection requested? -+ -- either has "Connection: keep-alive" header, -+ -- or is HTTP/1.1 and no header "Connection: close". -+ -+ is_http_version_1_0: BOOLEAN -+ do -+ Result := not attached version as v or else v.same_string ("HTTP/1.0") -+ end -+ -+ is_http_version_1_1: BOOLEAN -+ do -+ Result := not attached version as v or else v.same_string ("HTTP/1.1") -+ end -+ -+ is_http_version_2: BOOLEAN -+ do -+ Result := not attached version as v or else v.same_string ("HTTP/2.0") -+ end -+ -+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 and then max_keep_alive_requests > 0 -+ end -+ -+ 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. -+ -+feature -- Status report -+ -+ has_error: BOOLEAN -+ -- Error occurred during `analyze_request_message' -+ -+feature -- Change -+ -+ set_is_verbose (b: BOOLEAN) -+ -- Set `is_verbose' with `b'. -+ do -+ is_verbose := b -+ ensure -+ is_verbose_set: is_verbose = b -+ end -+ -+feature -- Execution -+ -+ safe_execute -+ -- Execute accepted incoming connection as request. -+ local -+ retried: BOOLEAN -+ do -+ if retried then -+ release -+ else -+ if -+ not has_error and then -+ is_connected -+ then -+ execute -+ end -+ release -+ end -+ rescue -+ retried := True -+ retry -+ end -+ -+ execute -+ require -+ is_connected: is_connected -+ local -+ l_socket: like client_socket -+ l_exit: BOOLEAN -+ 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 -+ end -+ 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 (n > 1) -+ l_exit := not is_persistent_connection_supported -+ 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 (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 -+ do -+ l_socket := client_socket -+ check -+ socket_attached: l_socket /= Void -+ socket_valid: l_socket.is_open_read and then l_socket.is_open_write -+ end -+ if l_socket.is_closed then -+ debug ("dbglog") -+ dbglog (generator + ".execute_request {socket is Closed!}") -+ end -+ else -+ debug ("dbglog") -+ dbglog (generator + ".execute_request socket=" + l_socket.descriptor.out + " ENTER") -+ end -+ -+ 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 -+ 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 -+ l_remote_info.hostname := l_addr.host_address.host_name -+ l_remote_info.port := l_addr.port -+ remote_info := l_remote_info -+ end -+ analyze_request_message (l_socket) -+ else -+ has_error := True -+ debug ("dbglog") -+ dbglog (generator + ".execute_request socket=" + l_socket.descriptor.out + "} timeout!") -+ end -+ end -+ -+ if has_error then -+ if l_is_ready then -+ -- check catch_bad_incoming_connection: False end -+ if is_verbose then -+ log (request_header + "%NWARNING: invalid HTTP incoming request", warning_level) -+ end -+ end -+ process_bad_request (l_socket) -+ is_persistent_connection_requested := False -+ else -+ if is_verbose then -+ log (request_header, information_level) -+ end -+ process_request (l_socket) -+ end -+ debug ("dbglog") -+ dbglog (generator + ".execute_request {" + l_socket.descriptor.out + "} LEAVE") -+ end -+ end -+ end -+ -+ release -+ do -+ reset -+ end -+ -+feature -- Request processing -+ -+ process_bad_request (a_socket: HTTPD_STREAM_SOCKET) -+ require -+ has_error: has_error -+ a_socket_attached: a_socket /= Void -+ local -+ h: STRING -+ s: STRING -+ do -+ s := "{ -+ -+ -+400 Bad Request -+ -+

Bad Request

-+ -+ }" -+ create h.make (1_024) -+ h.append ("HTTP/1.1 400 Bad Request%R%N") -+ h.append ("Content-Length: " + s.count.out + "%R%N") -+ h.append ("Connection: close%R%N") -+ h.append ("Content-Type: text/html; charset=iso-8859-1%R%N") -+ h.append ("%R%N") -+ a_socket.put_string (h) -+ a_socket.put_string (s) -+ end -+ -+ process_request (a_socket: HTTPD_STREAM_SOCKET) -+ -- Process request ... -+ require -+ no_error: not has_error -+ a_uri_attached: uri /= Void -+ a_method_attached: method /= Void -+ a_header_map_attached: request_header_map /= Void -+ a_header_text_attached: request_header /= Void -+ a_socket_attached: a_socket /= Void -+ deferred -+ end -+ -+feature -- Parsing -+ -+ analyze_request_message (a_socket: HTTPD_STREAM_SOCKET) -+ -- Analyze message extracted from `a_socket' as HTTP request -+ require -+ input_readable: a_socket /= Void and then a_socket.is_open_read -+ local -+ end_of_stream: BOOLEAN -+ pos, n: INTEGER -+ line: detachable STRING -+ k, val: STRING -+ txt: STRING -+ l_is_verbose: BOOLEAN -+ do -+ create txt.make (64) -+ request_header := txt -+ 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) -+ else -+ has_error := True -+ end -+ l_is_verbose := is_verbose -+ if not has_error then -+ from -+ line := next_line (a_socket) -+ until -+ line = Void or end_of_stream or has_error -+ loop -+ n := line.count -+ debug ("ew_standalone") -+ if l_is_verbose then -+ log (line, debug_level) -+ end -+ end -+ pos := line.index_of (':', 1) -+ if pos > 0 then -+ k := line.substring (1, pos - 1) -+ if line [pos + 1].is_space then -+ pos := pos + 1 -+ end -+ if line [n] = '%R' then -+ n := n - 1 -+ end -+ val := line.substring (pos + 1, n) -+ request_header_map.put (val, k) -+ end -+ txt.append (line) -+ txt.append_character ('%N') -+ if line.is_empty or else line [1] = '%R' then -+ end_of_stream := True -+ else -+ line := next_line (a_socket) -+ end -+ end -+ -- Except for HTTP/1.0, persistent connection is the default. -+ is_persistent_connection_requested := True -+ if is_http_version_1_0 then -+ is_persistent_connection_requested := attached request_header_map.item ("Connection") as l_connection and then -+ l_connection.is_case_insensitive_equal_general ("keep-alive") -+ else -+ -- By default HTTP:1/1 support persistent connection. -+ if attached request_header_map.item ("Connection") as l_connection then -+ if l_connection.is_case_insensitive_equal_general ("close") then -+ is_persistent_connection_requested := False -+ end -+ else -+ is_persistent_connection_requested := True -+ end -+ end -+ end -+ end -+ -+ analyze_request_line (line: STRING) -+ -- Analyze `line' as a HTTP request line -+ require -+ valid_line: line /= Void and then not line.is_empty -+ local -+ n, pos, next_pos: INTEGER -+ do -+ 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) -+ next_pos := line.index_of (' ', pos + 1) -+ uri := line.substring (pos + 1, next_pos - 1) -+ n := line.count -+ if line[n] = '%R' then -+ n := n - 1 -+ end -+ version := line.substring (next_pos + 1, n) -+ has_error := method.is_empty -+ end -+ -+ 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.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 -+ retry -+ end -+ -+feature -- Output -+ -+ logger: detachable HTTPD_LOGGER -+ -+ set_logger (a_logger: like logger) -+ -- Set `logger' with `a_logger'. -+ do -+ logger := a_logger -+ ensure -+ logger_set: logger = a_logger -+ end -+ -+ log (m: STRING; a_level: INTEGER) -+ -- Log message `m'. -+ require -+ is_verbose: is_verbose -+ do -+ 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 -+ -+invariant -+ request_header_attached: request_header /= Void -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_server_i.e b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_server_i.e -new file mode 100644 -index 0000000..3b1ac5d ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_server_i.e -@@ -0,0 +1,377 @@ -+note -+ description: "HTTPD server interface" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ HTTPD_SERVER_I -+ -+inherit -+ HTTPD_DEBUG_FACILITIES -+ -+ HTTPD_LOGGER -+ -+feature {NONE} -- Initialization -+ -+ make (a_factory: like factory) -+ -- Create current httpd server with `a_factory' of connection handlers. -+ -- `a_factory': connection handler builder -+ require -+ a_factory_is_separated: {PLATFORM}.is_scoop_capable implies not attached {HTTPD_REQUEST_HANDLER_FACTORY} a_factory -+ do -+ make_configured (create {like configuration}.make, a_factory) -+ end -+ -+ make_configured (a_cfg: like configuration; a_factory: like factory) -+ -- `a_cfg': server configuration -+ -- `a_factory': connection handler builder -+ do -+ configuration := a_cfg -+ factory := a_factory -+ -+ build_controller -+ -+ initialize -+ end -+ -+ build_controller -+ -- Build `controller'. -+ do -+ create controller -+ end -+ -+ initialize -+ -- Initialize Current server. -+ do -+ is_shutdown_requested := False -+ end -+ -+feature -- Access -+ -+ is_verbose: BOOLEAN -+ -- Is verbose for output messages. -+ -+ verbose_level: INTEGER -+ -- Verbosity of output. -+ -+ configuration: HTTPD_CONFIGURATION -+ -- Associated server configuration. -+ -+ controller: separate HTTPD_CONTROLLER -+ -+ factory: separate HTTPD_REQUEST_HANDLER_FACTORY -+ -+ is_persistent_connection_supported: BOOLEAN = True -+ -- Is persistent connection supported? -+ -+feature -- Callbacks -+ -+ observer: detachable separate HTTPD_SERVER_OBSERVER -+ -+ set_observer (obs: like observer) -+ -- Set `observer' to `obs'. -+ do -+ observer := obs -+ end -+ -+feature -- Access: listening -+ -+ port: INTEGER -+ -- Effective listening port. -+ --| If 0 then it is not launched successfully! -+ -+feature -- Status: listening -+ -+ is_launched: BOOLEAN -+ -- Server launched and listening on `port' -+ -+ is_terminated: BOOLEAN -+ -- Is terminated? -+ -+ is_shutdown_requested: BOOLEAN -+ -- Set true to stop accept loop -+ -+feature {NONE} -- Access: server -+ -+ request_counter: INTEGER -+ -- request counter, incremented for each new incoming connection. -+ -+feature -- Execution -+ -+ launch -+ do -+ apply_configuration -+ is_terminated := False -+ if is_verbose then -+ 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.has_ssl_support then -+ if configuration.is_secure then -+ log (" - SSL = enabled") -+ else -+ log (" - SSL = disabled") -+ end -+ else -+ log (" - SSL = not supported") -+ end -+ if configuration.verbose_level > 0 then -+ log (" - verbose_level = " + configuration.verbose_level.out) -+ end -+ end -+ is_shutdown_requested := False -+ listen -+ is_terminated := True -+ on_terminated -+ end -+ -+ shutdown_server -+ do -+ debug ("dbglog") -+ dbglog ("Shutdown requested") -+ end -+ is_shutdown_requested := True -+ controller_shutdown (controller) -+ end -+ -+ controller_shutdown (ctl: attached like controller) -+ do -+ ctl.shutdown -+ end -+ -+feature -- Listening -+ -+ listen -+ -- -+ -- Creates a socket and connects to the http server. -+ -- `a_server': The main server object -+ local -+ l_listening_socket: detachable HTTPD_STREAM_SOCKET -+ l_http_port: INTEGER -+ l_connection_handler: HTTPD_CONNECTION_HANDLER -+ do -+ is_terminated := False -+ is_launched := False -+ port := 0 -+ is_shutdown_requested := False -+ l_http_port := configuration.http_server_port -+ -+ if -+ attached configuration.http_server_name as l_servername and then -+ attached (create {INET_ADDRESS_FACTORY}).create_from_name (l_servername) as l_addr -+ then -+ l_listening_socket := new_listening_socket (l_addr, l_http_port) -+ else -+ l_listening_socket := new_listening_socket (Void, l_http_port) -+ end -+ -+ if not l_listening_socket.is_bound then -+ if is_verbose then -+ log ("Socket could not be bound on port " + l_http_port.out + " !") -+ end -+ else -+ l_http_port := l_listening_socket.port -+ create l_connection_handler.make (Current) -+ from -+ l_listening_socket.listen (configuration.max_tcp_clients) -+ if is_verbose then -+ if configuration.is_secure then -+ log ("%NListening on port " + l_http_port.out +" : https://localhost:" + l_http_port.out + "/") -+ else -+ log ("%NListening on port " + l_http_port.out +" : http://localhost:" + l_http_port.out + "/") -+ end -+ end -+ on_launched (l_http_port) -+ until -+ is_shutdown_requested -+ loop -+ request_counter := request_counter + 1 -+ if is_verbose then -+ log ("#" + request_counter.out + "# Waiting connection...(listening socket:" + l_listening_socket.descriptor.out + ")") -+ end -+ debug ("dbglog") -+ dbglog (generator + ".before process_waiting_incoming_connection") -+ end -+ l_connection_handler.accept_incoming_connection (l_listening_socket) -+ debug ("dbglog") -+ dbglog (generator + ".after process_waiting_incoming_connection") -+ end -+ -+ update_is_shutdown_requested (l_connection_handler) -+ end -+ wait_for_connection_handler_completion (l_connection_handler) -+ l_listening_socket.cleanup -+ check -+ socket_is_closed: l_listening_socket.is_closed -+ end -+ end -+ if is_launched then -+ on_stopped -+ end -+ if is_verbose then -+ log ("HTTP Connection Server ends.") -+ end -+ rescue -+ log ("HTTP Connection Server shutdown due to exception. Please relaunch manually.") -+ -+ if l_listening_socket /= Void then -+ l_listening_socket.cleanup -+ check -+ listening_socket_is_closed: l_listening_socket.is_closed -+ end -+ end -+ if is_launched then -+ on_stopped -+ end -+ is_shutdown_requested := True -+ retry -+ end -+ -+feature {NONE} -- Factory -+ -+ new_listening_socket (a_addr: detachable INET_ADDRESS; a_http_port: INTEGER): HTTPD_STREAM_SOCKET -+ do -+ if a_addr /= Void then -+ create Result.make_server_by_address_and_port (a_addr, a_http_port) -+ else -+ create Result.make_server_by_port (a_http_port) -+ end -+ end -+ -+feature {NONE} -- Helpers -+ -+ wait_for_connection_handler_completion (h: HTTPD_CONNECTION_HANDLER) -+ do -+ h.wait_for_completion -+ debug ("dbglog") -+ dbglog ("Shutdown ready from connection_handler point of view") -+ end -+ end -+ -+ update_is_shutdown_requested (a_connection_handler: HTTPD_CONNECTION_HANDLER) -+ do -+ is_shutdown_requested := is_shutdown_requested or shutdown_requested (controller) -+ if is_shutdown_requested then -+ a_connection_handler.shutdown -+ end -+ end -+ -+ shutdown_requested (a_controller: separate HTTPD_CONTROLLER): BOOLEAN -+ -- Shutdown requested on concurrent `a_controller'? -+ do -+ Result := a_controller.shutdown_requested -+ end -+ -+feature -- Event -+ -+ on_launched (a_port: INTEGER) -+ -- Server launched using port `a_port' -+ require -+ not_launched: not is_launched -+ do -+ is_launched := True -+ port := a_port -+ if attached observer as obs then -+ observer_on_launched (obs, a_port) -+ end -+ ensure -+ is_launched: is_launched -+ end -+ -+ on_stopped -+ -- Server stopped -+ require -+ is_launched: is_launched -+ do -+ if attached observer as obs then -+ observer_on_stopped (obs) -+ end -+ end -+ -+ on_terminated -+ -- Server terminated -+ require -+ is_terminated -+ do -+ if is_terminated and is_verbose then -+ log ("%N%NTerminating Web Application Server (port="+ port.out +"):%N") -+ end -+ if attached output as o then -+ o.flush -+ o.close -+ end -+ if attached observer as obs then -+ observer_on_terminated (obs) -+ end -+ end -+ -+feature {NONE} -- Separate event -+ -+ observer_on_launched (obs: attached like observer; a_port: INTEGER) -+ do -+ obs.on_launched (a_port) -+ end -+ -+ observer_on_stopped (obs: attached like observer) -+ do -+ obs.on_stopped -+ end -+ -+ observer_on_terminated (obs: attached like observer) -+ do -+ obs.on_terminated -+ end -+ -+feature -- Configuration change -+ -+ apply_configuration -+ require -+ is_not_launched: not is_launched -+ do -+ is_verbose := configuration.is_verbose -+ verbose_level := configuration.verbose_level -+ end -+ -+feature -- Output -+ -+ output: detachable FILE -+ -+ set_log_output (f: FILE) -+ -- Set `output' to `f'. -+ do -+ output := f -+ ensure -+ output_set: output = f -+ end -+ -+ log (a_message: separate READABLE_STRING_8) -+ -- Log `a_message'. -+ local -+ m: STRING -+ do -+ create m.make_from_separate (a_message) -+ if attached output as o then -+ o.put_string (m) -+ o.put_new_line -+ else -+ io.error.put_string (m) -+ io.error.put_new_line -+ end -+ end -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_server_observer.e b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_server_observer.e -new file mode 100644 -index 0000000..18a5998 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/httpd_server_observer.e -@@ -0,0 +1,27 @@ -+note -+ description: "Summary description for {HTTPD_SERVER_OBSERVER}." -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ HTTPD_SERVER_OBSERVER -+ -+feature -- Event -+ -+ on_launched (a_port: INTEGER) -+ -- Associated server launched listening on port `a_port'. -+ deferred -+ end -+ -+ on_stopped -+ -- Associated server stopped. -+ --| the server may restart itself after being rescued. -+ deferred -+ end -+ -+ on_terminated -+ -- Associated server terminated. -+ deferred -+ end -+ -+end -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/network/from_16_11/tcp_stream_socket_ext.e b/library/server/ewsgi/connectors/standalone/lib/httpd/network/from_16_11/tcp_stream_socket_ext.e -new file mode 100644 -index 0000000..65d4d70 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/network/from_16_11/tcp_stream_socket_ext.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/network/httpd_stream_socket.e b/library/server/ewsgi/connectors/standalone/lib/httpd/network/httpd_stream_socket.e -new file mode 100644 -index 0000000..76c0bb3 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/network/httpd_stream_socket.e -@@ -0,0 +1,358 @@ -+note -+ description: "[ -+ Summary description for {HTTPD_STREAM_SOCKET} -+ that can be used for http or https connection. -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ HTTPD_STREAM_SOCKET -+ -+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 -+ -+create {HTTPD_STREAM_SOCKET} -+ make -+ -+feature {NONE} -- Initialization -+ -+ make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER) -+ do -+ create {TCP_STREAM_SOCKET} socket.make_server_by_address_and_port (an_address, a_port) -+ end -+ -+ make_server_by_port (a_port: INTEGER) -+ do -+ 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 -+ do -+ create {TCP_STREAM_SOCKET} socket.make_from_separate (s.socket) -+ end -+ -+ make_empty -+ do -+ create {TCP_STREAM_SOCKET} socket.make_empty -+ end -+ -+ retrieve_socket (s: HTTPD_STREAM_SOCKET): INTEGER -+ do -+ Result := s.socket.descriptor -+ end -+ -+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) -+ end -+ end -+ -+ set_connect_timeout (n: INTEGER) -+ do -+ if attached {NETWORK_STREAM_SOCKET} socket as l_socket then -+ l_socket.set_connect_timeout (n) -+ end -+ end -+ -+ set_accept_timeout (n: INTEGER) -+ do -+ if attached {NETWORK_STREAM_SOCKET} socket as l_socket then -+ l_socket.set_accept_timeout (n) -+ 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 -+ do -+ Result := socket.last_string -+ end -+ -+ last_character: CHARACTER -+ do -+ Result := socket.last_character -+ end -+ -+ peer_address: detachable NETWORK_SOCKET_ADDRESS -+ -- Peer address of socket -+ do -+ if attached {NETWORK_SOCKET_ADDRESS} socket.peer_address as l_peer_address then -+ Result := l_peer_address -+ end -+ end -+ -+feature -- Input -+ -+ read_line_thread_aware -+ do -+ socket.read_line_thread_aware -+ end -+ -+ read_stream_thread_aware (nb: INTEGER) -+ do -+ socket.read_stream_thread_aware (nb) -+ end -+ -+ read_stream (nb: INTEGER) -+ do -+ socket.read_stream (nb) -+ end -+ -+ read_character -+ do -+ socket.read_character -+ end -+ -+ bytes_read: INTEGER -+ do -+ Result := socket.bytes_read -+ end -+ -+feature -- Output -+ -+ send_message (a_msg: STRING) -+ do -+ put_string (a_msg) -+ end -+ -+ put_readable_string_8 (s: READABLE_STRING_8) -+ -- Write readable string `s' to socket. -+ do -+ if attached {TCP_STREAM_SOCKET} socket as l_tcp_stream_socket then -+ l_tcp_stream_socket.put_readable_string_8 (s) -+ else -+ put_string (s) -+ end -+ end -+ -+ put_string (s: STRING) -+ do -+ socket.put_string (s) -+ end -+ -+ put_character (c: CHARACTER) -+ do -+ socket.put_character (c) -+ end -+ -+feature -- Status Report -+ -+ descriptor_available: BOOLEAN -+ -- Is descriptor available? -+ do -+ Result := socket.descriptor_available -+ end -+ -+ descriptor: INTEGER -+ do -+ Result := socket.descriptor -+ end -+ -+ port: INTEGER -+ do -+ if attached {TCP_STREAM_SOCKET} socket as l_socket then -+ Result := l_socket.port -+ end -+ end -+ -+ exists: BOOLEAN -+ do -+ Result := socket.exists -+ end -+ -+ is_blocking: BOOLEAN -+ do -+ Result := socket.is_blocking -+ end -+ -+ is_bound: BOOLEAN -+ do -+ if attached {TCP_STREAM_SOCKET} socket as l_socket then -+ Result := l_socket.is_bound -+ 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 -+ Result := l_socket.is_created -+ end -+ end -+ -+ socket_ok: BOOLEAN -+ do -+ Result := socket.socket_ok -+ end -+ -+ is_open_read: BOOLEAN -+ do -+ Result := socket.is_open_read -+ end -+ -+ is_open_write: BOOLEAN -+ do -+ Result := socket.is_open_write -+ end -+ -+ is_closed: BOOLEAN -+ do -+ Result := socket.is_closed -+ end -+ -+ is_readable: BOOLEAN -+ do -+ Result := socket.is_readable -+ end -+ -+ cleanup -+ do -+ socket.cleanup -+ end -+ -+ ready_for_writing: BOOLEAN -+ do -+ if attached {TCP_STREAM_SOCKET} socket as l_socket then -+ Result := l_socket.ready_for_writing -+ end -+ end -+ -+ connect -+ do -+ socket.connect -+ end -+ -+ close -+ do -+ socket.close -+ end -+ -+ listen (a_queue: INTEGER) -+ do -+ socket.listen (a_queue) -+ end -+ -+ accept -+ do -+ socket.accept -+ end -+ -+ accept_to (other: separate HTTPD_STREAM_SOCKET) -+ -- Accept a new connection on listen socket. -+ -- Socket of accepted connection is available in `other'. -+ do -+ if -+ attached {NETWORK_STREAM_SOCKET} socket as l_socket and then -+ attached {separate NETWORK_STREAM_SOCKET} other.socket as l_other_socket -+ then -+ l_socket.accept_to (l_other_socket) -+ end -+ end -+ -+ set_blocking -+ do -+ socket.set_blocking -+ end -+ -+ set_non_blocking -+ do -+ socket.set_non_blocking -+ end -+ -+ readable: BOOLEAN -+ do -+ Result := socket.readable -+ end -+ -+ ready_for_reading: BOOLEAN -+ do -+ if attached {TCP_STREAM_SOCKET} socket as l_socket then -+ Result := l_socket.ready_for_reading -+ end -+ end -+ -+ try_ready_for_reading: BOOLEAN -+ do -+ if attached {TCP_STREAM_SOCKET} socket as l_socket then -+ Result := l_socket.try_ready_for_reading -+ end -+ end -+ -+ accepted: detachable HTTPD_STREAM_SOCKET -+ do -+ if attached {NETWORK_STREAM_SOCKET} socket.accepted as l_accepted then -+ create Result.make (l_accepted) -+ end -+ end -+ -+feature {HTTPD_STREAM_SOCKET} -- Implementation -+ -+ make (a_socket: STREAM_SOCKET) -+ do -+ socket := a_socket -+ end -+ -+ socket: STREAM_SOCKET -+ -+ network_stream_socket: detachable NETWORK_STREAM_SOCKET -+ do -+ if attached {NETWORK_STREAM_SOCKET} socket as s then -+ Result := s -+ end -+ end -+ -+;note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/network/ssl/httpd_stream_ssl_socket.e b/library/server/ewsgi/connectors/standalone/lib/httpd/network/ssl/httpd_stream_ssl_socket.e -new file mode 100644 -index 0000000..1217d0d ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/network/ssl/httpd_stream_ssl_socket.e -@@ -0,0 +1,169 @@ -+note -+ description: "[ -+ Summary description for {HTTPD_STREAM_SSL_SOCKET} -+ that can be used for http or https connection. -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ HTTPD_STREAM_SSL_SOCKET -+ -+inherit -+ HTTPD_STREAM_SOCKET -+ redefine -+ port, -+ is_bound, -+ ready_for_writing, -+ ready_for_reading, -+ try_ready_for_reading, -+ 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_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_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_fn, a_key_fn) -+ end -+ -+ 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_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 -+ -- . -+ do -+ create {SSL_TCP_STREAM_SOCKET} socket.make_empty -+ end -+ -+feature -- Output -+ -+ put_readable_string_8 (s: READABLE_STRING_8) -+ -- -+ do -+ if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then -+ l_ssl_socket.put_readable_string_8 (s) -+ else -+ Precursor (s) -+ end -+ end -+ -+feature -- Status Report -+ -+ port: INTEGER -+ -- -+ do -+ if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then -+ Result := l_ssl_socket.port -+ else -+ Result := Precursor -+ end -+ end -+ -+ is_bound: BOOLEAN -+ -- -+ do -+ if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then -+ Result := l_ssl_socket.is_bound -+ else -+ Result := Precursor -+ end -+ end -+ -+ ready_for_writing: BOOLEAN -+ -- -+ do -+ if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then -+ Result := l_ssl_socket.ready_for_writing -+ else -+ Result := Precursor -+ end -+ end -+ -+ ready_for_reading: BOOLEAN -+ -- -+ do -+ if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then -+ Result := l_ssl_socket.ready_for_reading -+ else -+ Result := Precursor -+ end -+ end -+ -+ try_ready_for_reading: BOOLEAN -+ do -+ if attached {SSL_TCP_STREAM_SOCKET} socket as l_socket then -+ Result := l_socket.try_ready_for_reading -+ else -+ Result := Precursor -+ end -+ end -+ -+feature {HTTPD_STREAM_SOCKET} -- Implementation -+ -+ set_certificates (a_crt_filename, a_key_filename: detachable READABLE_STRING_GENERAL) -+ do -+ if attached {SSL_NETWORK_STREAM_SOCKET} socket as l_socket then -+ 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 -+ -+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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/network/ssl/ssl_tcp_stream_socket.e b/library/server/ewsgi/connectors/standalone/lib/httpd/network/ssl/ssl_tcp_stream_socket.e -new file mode 100644 -index 0000000..de71f47 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/network/ssl/ssl_tcp_stream_socket.e -@@ -0,0 +1,73 @@ -+note -+ description: "SSL tcp stream socket." -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ SSL_TCP_STREAM_SOCKET -+ -+inherit -+ -+ SSL_NETWORK_STREAM_SOCKET -+ -+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} -+ make_from_descriptor_and_address -+ -+feature {NONE} -- Initialization -+ -+ make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER) -+ -- Create server socket on `an_address' and `a_port'. -+ require -+ valid_port: a_port >= 0 -+ do -+ make -+ create address.make_from_address_and_port (an_address, a_port) -+ bind -+ end -+ -+feature -- Basic operation -+ -+ send_message (a_msg: STRING) -+ do -+ put_string (a_msg) -+ end -+ -+feature -- Output -+ -+ put_readable_string_8 (s: READABLE_STRING_8) -+ -- Write readable string `s' to socket. -+ local -+ ext: C_STRING -+ do -+ create ext.make (s) -+ put_managed_pointer (ext.managed_data, 0, s.count) -+ end -+ -+feature -- Status report -+ -+ try_ready_for_reading: BOOLEAN -+ -- Is data available for reading from the socket right now? -+ require -+ socket_exists: exists -+ local -+ retval: INTEGER -+ do -+ retval := c_select_poll_with_timeout (descriptor, True, 0) -+ Result := (retval > 0) -+ end -+ -+feature {NONE}-- Implementation -+ -+ -+ -+ -+note -+ copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others" -+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" -+ -+end -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/network/tcp_stream_socket.e b/library/server/ewsgi/connectors/standalone/lib/httpd/network/tcp_stream_socket.e -new file mode 100644 -index 0000000..6961a77 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/network/tcp_stream_socket.e -@@ -0,0 +1,98 @@ -+note -+ description: "Summary description for {TCP_STREAM_SOCKET}." -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ TCP_STREAM_SOCKET -+ -+inherit -+ NETWORK_STREAM_SOCKET -+ redefine -+ 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 -+ -+create {NETWORK_STREAM_SOCKET} -+ make_from_descriptor_and_address -+ -+feature {NONE} -- Initialization -+ -+ make -+ -- Create a network stream socket. -+ do -+ Precursor -+ debug -+ set_reuse_address -+ end -+ end -+ -+ make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER) -+ -- Create server socket on `an_address' and `a_port'. -+ require -+ valid_port: a_port >= 0 -+ do -+ make -+ create address.make_from_address_and_port (an_address, a_port) -+ bind -+ end -+ -+ make_from_separate (s: separate STREAM_SOCKET) -+ require -+ descriptor_available: s.descriptor_available -+ do -+ create_from_descriptor (s.descriptor) -+ end -+ -+feature -- Basic operation -+ -+ send_message (a_msg: STRING) -+ do -+ put_string (a_msg) -+ end -+ -+feature -- Output -+ -+ put_readable_string_8 (s: READABLE_STRING_8) -+ -- Write readable string `s' to socket. -+ local -+ ext: C_STRING -+ do -+ create ext.make (s) -+ put_managed_pointer (ext.managed_data, 0, s.count) -+ end -+ -+feature -- Status report -+ -+ try_ready_for_reading: BOOLEAN -+ -- Is data available for reading from the socket right now? -+ require -+ socket_exists: exists -+ local -+ retval: INTEGER -+ do -+ retval := c_select_poll_with_timeout (descriptor, True, 0) -+ Result := (retval > 0) -+ end -+ -+note -+ copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/network/until_16_05/tcp_stream_socket_ext.e b/library/server/ewsgi/connectors/standalone/lib/httpd/network/until_16_05/tcp_stream_socket_ext.e -new file mode 100644 -index 0000000..73480ca ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/network/until_16_05/tcp_stream_socket_ext.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/no_ssl/httpd_configuration.e b/library/server/ewsgi/connectors/standalone/lib/httpd/no_ssl/httpd_configuration.e -new file mode 100644 -index 0000000..65ae18c ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/no_ssl/httpd_configuration.e -@@ -0,0 +1,66 @@ -+note -+ description: "Standalone server configuration (ssl NOT supported)." -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ HTTPD_CONFIGURATION -+ -+inherit -+ HTTPD_CONFIGURATION_I -+ -+create -+ make -+ -+feature -- Status -+ -+ Server_details: STRING_8 = "Server: Standalone Eiffel Server" -+ -+ has_ssl_support: BOOLEAN = False -+ -- Precursor -+ -+feature -- SSL Helpers -+ -+ set_ssl_protocol_to_ssl_2_or_3 -+ -- Set `ssl_protocol' with `Ssl_23'. -+ do -+ -- Ignored -+ end -+ -+ -+ set_ssl_protocol_to_tls_1_0 -+ -- Set `ssl_protocol' with `Tls_1_0'. -+ do -+ -- Ignored -+ end -+ -+ set_ssl_protocol_to_tls_1_1 -+ -- Set `ssl_protocol' with `Tls_1_1'. -+ do -+ -- Ignored -+ end -+ -+ set_ssl_protocol_to_tls_1_2 -+ -- Set `ssl_protocol' with `Tls_1_2'. -+ do -+ -- Ignored -+ end -+ -+ set_ssl_protocol_to_dtls_1_0 -+ -- Set `ssl_protocol' with `Dtls_1_0'. -+ do -+ -- Ignored -+ 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/no_ssl/httpd_server.e b/library/server/ewsgi/connectors/standalone/lib/httpd/no_ssl/httpd_server.e -new file mode 100644 -index 0000000..8787e1f ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/no_ssl/httpd_server.e -@@ -0,0 +1,27 @@ -+note -+ description: "[ -+ httpd server -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ HTTPD_SERVER -+ -+inherit -+ HTTPD_SERVER_I -+ -+create -+ make -+ -+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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/no_ssl/httpd_socket_factory.e b/library/server/ewsgi/connectors/standalone/lib/httpd/no_ssl/httpd_socket_factory.e -new file mode 100644 -index 0000000..6c08bc3 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/no_ssl/httpd_socket_factory.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/package.iron b/library/server/ewsgi/connectors/standalone/lib/httpd/package.iron -new file mode 100644 -index 0000000..bb34ce9 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/package.iron -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/ssl/httpd_configuration.e b/library/server/ewsgi/connectors/standalone/lib/httpd/ssl/httpd_configuration.e -new file mode 100644 -index 0000000..b7eba79 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/ssl/httpd_configuration.e -@@ -0,0 +1,79 @@ -+note -+ description: "Standalone server configuration (ssl supported)." -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ HTTPD_CONFIGURATION -+ -+inherit -+ HTTPD_CONFIGURATION_I -+ redefine -+ make -+ end -+ -+create -+ make -+ -+feature {NONE} -- Initialization -+ -+ make -+ -- Create a new instance and set ssl protocol to tls_1_2. -+ do -+ Precursor -+ set_ssl_protocol_to_tls_1_2 -+ ensure then -+ ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.tls_1_2 -+ end -+ -+feature -- Access -+ -+ Server_details: STRING_8 = "Server: Standalone Eiffel Server (https)" -+ -+ has_ssl_support: BOOLEAN = True -+ -- Precursor -+ -+feature -- SSL Helpers -+ -+ set_ssl_protocol_to_ssl_2_or_3 -+ -- Set `ssl_protocol' with `Ssl_23'. -+ do -+ set_ssl_protocol ({SSL_PROTOCOL}.Ssl_23) -+ end -+ -+ set_ssl_protocol_to_tls_1_0 -+ -- Set `ssl_protocol' with `Tls_1_0'. -+ do -+ set_ssl_protocol ({SSL_PROTOCOL}.Tls_1_0) -+ end -+ -+ set_ssl_protocol_to_tls_1_1 -+ -- Set `ssl_protocol' with `Tls_1_1'. -+ do -+ set_ssl_protocol ({SSL_PROTOCOL}.Tls_1_1) -+ end -+ -+ set_ssl_protocol_to_tls_1_2 -+ -- Set `ssl_protocol' with `Tls_1_2'. -+ do -+ set_ssl_protocol ({SSL_PROTOCOL}.Tls_1_2) -+ end -+ -+ set_ssl_protocol_to_dtls_1_0 -+ -- Set `ssl_protocol' with `Dtls_1_0'. -+ do -+ set_ssl_protocol ({SSL_PROTOCOL}.Dtls_1_0) -+ 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 -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/ssl/httpd_server.e b/library/server/ewsgi/connectors/standalone/lib/httpd/ssl/httpd_server.e -new file mode 100644 -index 0000000..4045aa2 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/ssl/httpd_server.e -@@ -0,0 +1,35 @@ -+note -+ description: "[ -+ SSL enabled server -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ HTTPD_SERVER -+ -+inherit -+ HTTPD_SERVER_I -+ redefine -+ new_listening_socket -+ end -+ -+create -+ make -+ -+feature {NONE} -- Factory -+ -+ new_listening_socket (a_addr: detachable INET_ADDRESS; a_http_port: INTEGER): HTTPD_STREAM_SOCKET -+ do -+ if configuration.is_secure then -+ if a_addr /= Void then -+ create {HTTPD_STREAM_SSL_SOCKET} Result.make_ssl_server_by_address_and_port (a_addr, a_http_port, configuration.ssl_protocol, configuration.ca_crt, configuration.ca_key) -+ else -+ create {HTTPD_STREAM_SSL_SOCKET} Result.make_ssl_server_by_port (a_http_port, configuration.ssl_protocol, configuration.ca_crt, configuration.ca_key) -+ end -+ else -+ Result := Precursor (a_addr, a_http_port) -+ end -+ end -+ -+end -diff --git a/library/server/ewsgi/connectors/standalone/lib/httpd/ssl/httpd_socket_factory.e b/library/server/ewsgi/connectors/standalone/lib/httpd/ssl/httpd_socket_factory.e -new file mode 100644 -index 0000000..ff410db ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/lib/httpd/ssl/httpd_socket_factory.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/none/httpd_connection_handler.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/none/httpd_connection_handler.e -deleted file mode 100644 -index 5bc857c..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/none/httpd_connection_handler.e -+++ /dev/null -@@ -1,86 +0,0 @@ --note -- description: "[ -- Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: none -- ]" -- date: "$Date$" -- revision: "$Revision$" -- --class -- HTTPD_CONNECTION_HANDLER -- --inherit -- HTTPD_CONNECTION_HANDLER_I -- --create -- make -- --feature {NONE} -- Initialization -- -- initialize -- do -- end -- --feature -- Access -- -- is_shutdown_requested: BOOLEAN -- -- -- -- shutdown_requested (a_server: like server): BOOLEAN -- do -- -- FIXME: we should probably remove this possibility, check with EWF if this is needed. -- Result := a_server.controller.shutdown_requested -- end -- --feature {HTTPD_SERVER_I} -- Execution -- -- accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET) -- local -- cl: HTTPD_STREAM_SOCKET -- do -- is_shutdown_requested := is_shutdown_requested or shutdown_requested (server) -- if is_shutdown_requested then -- -- Cancel -- elseif attached factory.new_handler as h then -- cl := h.client_socket -- a_listening_socket.accept_to (cl) -- if h.is_connected then -- h.safe_execute -- end -- else -- check is_not_full: False end -- end -- update_is_shutdown_requested -- end -- -- update_is_shutdown_requested -- do -- is_shutdown_requested := shutdown_requested (server) -- end -- -- shutdown -- do -- if not is_shutdown_requested then -- is_shutdown_requested := True -- server.controller.shutdown -- end -- end -- --feature {HTTPD_SERVER_I} -- Status report -- -- wait_for_completion -- -- Wait until Current is ready for shutdown -- do -- -- no concurrency, then current task should be done. -- end -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/none/httpd_request_handler.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/none/httpd_request_handler.e -deleted file mode 100644 -index c033de7..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/none/httpd_request_handler.e -+++ /dev/null -@@ -1,32 +0,0 @@ --note -- description : "Concurrent specific feature to implement HTTPD_REQUEST_HANDLER" -- date : "$Date$" -- revision : "$Revision$" -- --deferred class -- HTTPD_REQUEST_HANDLER -- --inherit -- HTTPD_REQUEST_HANDLER_I -- redefine -- is_persistent_connection_supported -- end -- --feature -- Status report -- -- is_persistent_connection_supported: BOOLEAN = False -- -- -- -- When there is no concurrency support, do not try to support -- -- persistent connection! -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/none/httpd_request_handler_factory.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/none/httpd_request_handler_factory.e -deleted file mode 100644 -index 1c93e9e..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/none/httpd_request_handler_factory.e -+++ /dev/null -@@ -1,15 +0,0 @@ --note -- description: "Implementation of request handler factory for concurrency mode: none" -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- HTTPD_REQUEST_HANDLER_FACTORY -- --inherit -- HTTPD_REQUEST_HANDLER_FACTORY_I -- --note -- copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others" -- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" --end -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/httpd_connection_handler.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/httpd_connection_handler.e -deleted file mode 100644 -index 9a5f466..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/httpd_connection_handler.e -+++ /dev/null -@@ -1,146 +0,0 @@ --note -- description: "[ -- Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: SCOOP -- ]" -- date: "$Date$" -- revision: "$Revision$" -- --class -- HTTPD_CONNECTION_HANDLER -- --inherit -- HTTPD_CONNECTION_HANDLER_I -- redefine -- initialize -- end -- --create -- make -- --feature {NONE} -- Initialization -- -- initialize -- local -- n: INTEGER -- p: like pool -- do -- n := max_concurrent_connections (server) -- create p.make (n) -- initialize_pool (p, n) -- pool := p -- end -- -- initialize_pool (p: like pool; n: INTEGER) -- -- Initialize Concurrent pool of `n' potential separate connection handlers. -- do -- p.set_count (n) -- end -- --feature -- Access -- -- is_shutdown_requested: BOOLEAN -- -- -- -- max_concurrent_connections (a_server: like server): INTEGER -- -- Max concurrent connection settings from server `a_server'. -- do -- Result := a_server.configuration.max_concurrent_connections -- end -- --feature {HTTPD_SERVER_I} -- Execution -- -- shutdown -- -- -- do -- if not is_shutdown_requested then -- is_shutdown_requested := True -- pool_gracefull_stop (pool) -- end -- end -- -- pool_gracefull_stop (p: like pool) -- -- Graceful stop concurrent pool of separate connection handlers. -- do -- p.gracefull_stop -- end -- -- accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET) -- -- -- do -- accept_connection_on_pool (pool, a_listening_socket) -- Wait on not pool.is_full or is_stop_requested -- end -- -- accept_connection_on_pool (a_pool: like pool; a_listening_socket: HTTPD_STREAM_SOCKET) -- -- Process accept connection -- -- note that the precondition matters for scoop synchronization. -- require -- concurrency: not a_pool.is_full or is_shutdown_requested or a_pool.stop_requested -- local -- cl: separate HTTPD_STREAM_SOCKET -- do -- debug ("dbglog") -- dbglog (generator + ".ENTER accept_connection_on_pool") -- end -- if is_shutdown_requested then -- -- Cancel -- elseif attached a_pool.separate_item (factory) as h then -- cl := separate_client_socket (h) -- a_listening_socket.accept_to (cl) -- process_handler (h) -- else -- check is_not_full: False end -- end -- debug ("dbglog") -- dbglog (generator + ".LEAVE accept_connection_on_pool") -- end -- end -- -- process_handler (hdl: separate HTTPD_REQUEST_HANDLER) -- -- Process request handler `hdl' as soon as `hdl' is connected to accepted socket. -- require -- hdl.is_connected -- do -- hdl.safe_execute -- end -- --feature {HTTPD_SERVER_I} -- Status report -- -- wait_for_completion -- -- Wait until Current is ready for shutdown. -- do -- wait_for_pool_completion (pool) -- end -- -- wait_for_pool_completion (p: like pool) -- -- Wait until concurrent pool is empty and terminated. -- require -- p.is_empty -- SCOOP wait condition. -- do -- p.terminate -- end -- --feature {NONE} -- Implementation -- -- separate_client_socket (hdl: separate HTTPD_REQUEST_HANDLER): separate HTTPD_STREAM_SOCKET -- -- Client socket for request handler `hdl'. -- do -- Result := hdl.client_socket -- end -- -- pool: separate CONCURRENT_POOL [HTTPD_REQUEST_HANDLER] -- -- Pool of separate connection handlers. -- --invariant -- pool_attached: pool /= Void -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/httpd_request_handler.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/httpd_request_handler.e -deleted file mode 100644 -index 9335e76..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/httpd_request_handler.e -+++ /dev/null -@@ -1,55 +0,0 @@ --note -- description: "[ -- Instance of HTTPD_REQUEST_HANDLER will process the incoming connection -- and extract information on the request and the server -- ]" -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- HTTPD_REQUEST_HANDLER -- --inherit -- HTTPD_REQUEST_HANDLER_I -- redefine -- release -- end -- -- CONCURRENT_POOL_ITEM -- rename -- release as release_pool_item -- end -- --feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation -- -- release -- -- -- local -- d: STRING -- do -- if attached internal_client_socket as l_socket then -- d := l_socket.descriptor.out -- else -- d := "N/A" -- end -- debug ("dbglog") -- dbglog (generator + ".release: ENTER {" + d + "}") -- end -- Precursor {HTTPD_REQUEST_HANDLER_I} -- release_pool_item -- debug ("dbglog") -- dbglog (generator + ".release: LEAVE {" + d + "}") -- end -- end -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/httpd_request_handler_factory.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/httpd_request_handler_factory.e -deleted file mode 100644 -index e48a96a..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/httpd_request_handler_factory.e -+++ /dev/null -@@ -1,27 +0,0 @@ --note -- description: "Implementation of request handler factory for concurrency mode: SCOOP" -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- HTTPD_REQUEST_HANDLER_FACTORY -- --inherit -- HTTPD_REQUEST_HANDLER_FACTORY_I -- -- CONCURRENT_POOL_FACTORY [HTTPD_REQUEST_HANDLER] -- rename -- new_separate_item as new_handler -- end -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/pool/concurrent_pool.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/pool/concurrent_pool.e -deleted file mode 100644 -index 070f271..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/pool/concurrent_pool.e -+++ /dev/null -@@ -1,190 +0,0 @@ --note -- description: "Concurrent pool for SCOOP concurrency mode." -- date: "$Date$" -- revision: "$Revision$" -- --class -- CONCURRENT_POOL [G -> CONCURRENT_POOL_ITEM] -- --inherit -- HTTPD_DEBUG_FACILITIES -- --create -- make -- --feature {NONE} -- Initialization -- -- make (n: INTEGER) -- do -- capacity := n -- create items.make_empty (n) -- create busy_items.make_empty (n) -- end -- --feature -- Access -- -- count: INTEGER -- -- Number of concurrent items managed by Current pool. -- -- capacity: INTEGER -- -- Maximum number of concurrent items managed by Current pool. -- --feature -- Status report -- -- is_full: BOOLEAN -- -- Pool is full? -- do -- Result := count >= capacity -- end -- -- is_empty: BOOLEAN -- -- No concurrent item waiting in current pool. -- do -- Result := count = 0 -- end -- -- stop_requested: BOOLEAN -- -- Current pool received a request to terminate. -- --feature -- Access -- -- separate_item (a_factory: separate CONCURRENT_POOL_FACTORY [G]): detachable separate G -- -- Reused, or new separate item of type {G} created by `a_factory'. -- require -- is_not_full: not is_full -- local -- i,n,pos: INTEGER -- lst: like busy_items -- l_item: detachable separate G -- do -- if not stop_requested then -- from -- lst := busy_items -- pos := -1 -- i := 0 -- n := lst.count - 1 -- until -- i > n or l_item /= Void or pos >= 0 -- loop -- if not lst [i] then -- is free (i.e not busy) -- pos := i -- -- if items.valid_index (pos) then -- l_item := items [pos] -- if l_item /= Void then -- busy_items [pos] := True -- end -- end -- if l_item = Void then -- -- Empty, then let's create one. -- l_item := a_factory.new_separate_item -- register_item (l_item) -- items [pos] := l_item -- end -- end -- i := i + 1 -- end -- if l_item = Void then -- -- Pool is FULL ... -- check overcapacity: False end -- else -- debug ("pool", "dbglog") -- dbglog ("Lock pool item #" + pos.out + " (free:"+ (capacity - count).out +"))") -- end -- count := count + 1 -- busy_items [pos] := True -- Result := l_item -- a_factory.update_item (l_item) -- end -- end -- end -- --feature -- Basic operation -- -- gracefull_stop -- -- Request the Current pool to terminate. -- do -- stop_requested := True -- end -- --feature {NONE} -- Internal -- -- items: SPECIAL [detachable separate G] -- -- List of concurrent items. -- -- busy_items: SPECIAL [BOOLEAN] -- -- Map of items being proceed. -- --feature {CONCURRENT_POOL_ITEM} -- Change -- -- release_item (a_item: separate G) -- -- Unregister `a_item' from Current pool. -- require -- count > 0 -- local -- i,n,pos: INTEGER -- lst: like items -- do -- -- release handler for reuse -- from -- lst := items -- i := 0 -- n := lst.count - 1 -- until -- i > n or lst [i] = a_item -- loop -- i := i + 1 -- end -- if i <= n then -- pos := i -- busy_items [pos] := False -- count := count - 1 ----reuse items [pos] := Void -- debug ("pool", "dbglog") -- dbglog ("Released pool item #" + i.out + " (free:"+ (capacity - count).out +"))") -- end -- else -- check known_item: False end -- end -- end -- --feature -- Change -- -- set_count (n: INTEGER) -- -- Set capacity of Current pool to `n'. -- local -- g: detachable separate G -- do -- capacity := n -- items.fill_with (g, 0, n - 1) -- busy_items.fill_with (False, 0, n - 1) -- end -- -- terminate -- -- Terminate current pool. -- local -- l_items: like items -- do -- l_items := items -- l_items.wipe_out -- end -- --feature {NONE} -- Implementation -- -- register_item (a_item: separate G) -- -- Adopt `a_item' in current pool. -- do -- a_item.set_pool (Current) -- end -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/pool/concurrent_pool_factory.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/pool/concurrent_pool_factory.e -deleted file mode 100644 -index 92e0f2c..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/pool/concurrent_pool_factory.e -+++ /dev/null -@@ -1,31 +0,0 @@ --note -- description: "Factory in charge of creating new concurrent pool item." -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- CONCURRENT_POOL_FACTORY [G -> CONCURRENT_POOL_ITEM] -- --feature -- Access -- -- update_item (a_item: separate G) -- -- Update `a_item' for optionally purpose. -- do -- end -- -- new_separate_item: separate G -- -- New separated object of type {G}. -- deferred -- end -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/pool/concurrent_pool_item.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/pool/concurrent_pool_item.e -deleted file mode 100644 -index 2b5d1c6..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/scoop/pool/concurrent_pool_item.e -+++ /dev/null -@@ -1,52 +0,0 @@ --note -- description: "[ -- Item create by the CONCURRENT_POOL_FACTORY, and managed by the CONCURRENT_POOL -- for SCOOP concurrency mode. -- ]" -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- CONCURRENT_POOL_ITEM -- --feature {NONE} -- Access -- -- pool: detachable separate CONCURRENT_POOL [CONCURRENT_POOL_ITEM] -- -- Associated concurrent pool component. -- --feature {CONCURRENT_POOL} -- Change -- -- set_pool (p: like pool) -- -- Set associated `pool' to `p'. -- do -- pool := p -- end -- --feature {CONCURRENT_POOL, HTTPD_CONNECTION_HANDLER_I} -- Basic operation -- -- release -- -- Release Current pool item from associated pool. -- do -- if attached pool as p then -- pool_release (p) -- end -- end -- --feature {NONE} -- Implementation -- -- pool_release (p: separate CONCURRENT_POOL [CONCURRENT_POOL_ITEM]) -- do -- p.release_item (Current) -- end -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/httpd_connection_handler.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/httpd_connection_handler.e -deleted file mode 100644 -index 45b85bd..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/httpd_connection_handler.e -+++ /dev/null -@@ -1,103 +0,0 @@ --note -- description: "[ -- Implementation of HTTPD_CONNECTION_HANDLER_I for concurrency mode: Thread -- ]" -- date: "$Date$" -- revision: "$Revision$" -- --class -- HTTPD_CONNECTION_HANDLER -- --inherit -- HTTPD_CONNECTION_HANDLER_I -- redefine -- initialize -- end -- --create -- make -- --feature {NONE} -- Initialization -- -- initialize -- local -- n: INTEGER -- do -- n := max_concurrent_connections (server) -- create pool.make (n.to_natural_32) -- end -- --feature -- Access -- -- is_shutdown_requested: BOOLEAN -- -- max_concurrent_connections (a_server: like server): INTEGER -- do -- Result := a_server.configuration.max_concurrent_connections -- end -- --feature {HTTPD_SERVER_I} -- Execution -- -- shutdown -- do -- if not is_shutdown_requested then -- is_shutdown_requested := True -- pool_gracefull_stop (pool) -- end -- end -- -- pool_gracefull_stop (p: like pool) -- do -- p.terminate -- end -- -- accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET) -- local -- cl: separate HTTPD_STREAM_SOCKET -- do -- debug ("dbglog") -- dbglog (generator + ".ENTER accept_connection {"+ a_listening_socket.descriptor.out +"}") -- end -- -- if is_shutdown_requested then -- -- cancel -- elseif attached factory.new_handler as h then -- cl := h.client_socket -- a_listening_socket.accept_to (cl) -- if h.is_connected then -- pool.add_work (agent h.safe_execute) -- end -- end -- -- debug ("dbglog") -- dbglog (generator + ".LEAVE accept_incoming_connection {"+ a_listening_socket.descriptor.out +"}") -- end -- end -- --feature {HTTPD_SERVER_I} -- Status report -- -- wait_for_completion -- -- Wait until Current is ready for shutdown -- do -- pool.wait_for_completion -- end -- --feature {NONE} -- Access -- -- pool: THREAD_POOL [HTTPD_REQUEST_HANDLER] --ANY] --POOLED_THREAD [HTTP_REQUEST_HANDLER]] -- -- Pool of concurrent connection handlers. -- --invariant -- pool_attached: pool /= Void -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/httpd_request_handler.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/httpd_request_handler.e -deleted file mode 100644 -index e053bfe..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/httpd_request_handler.e -+++ /dev/null -@@ -1,49 +0,0 @@ --note -- description: "[ -- Instance of HTTPD_REQUEST_HANDLER will process the incoming connection -- and extract information on the request and the server -- ]" -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- HTTPD_REQUEST_HANDLER -- --inherit -- HTTPD_REQUEST_HANDLER_I -- redefine -- release -- end -- --feature {HTTPD_CONNECTION_HANDLER_I} -- Basic operation -- -- release -- local -- d: 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") -- dbglog (generator + ".release: ENTER {" + d + "}") -- end -- Precursor {HTTPD_REQUEST_HANDLER_I} -- debug ("dbglog") -- dbglog (generator + ".release: LEAVE {" + d + "}") -- end -- end -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/httpd_request_handler_factory.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/httpd_request_handler_factory.e -deleted file mode 100644 -index cf692e5..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/httpd_request_handler_factory.e -+++ /dev/null -@@ -1,15 +0,0 @@ --note -- description: "Implementation of request handler factory for concurrency mode: Thread" -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- HTTPD_REQUEST_HANDLER_FACTORY -- --inherit -- HTTPD_REQUEST_HANDLER_FACTORY_I -- --note -- copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others" -- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" --end -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/pool/pooled_thread.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/pool/pooled_thread.e -deleted file mode 100644 -index 393e028..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/pool/pooled_thread.e -+++ /dev/null -@@ -1,121 +0,0 @@ --note -- description: "{POOLED_THREAD} is used in combination with {THREAD_POOL} to allow for pooled threads." -- legal: "See notice at end of class." -- status: "Community Preview 1.0" -- date: "$Date: 2009-09-01 19:15:37 -0300 (mar 01 de sep de 2009) $" -- revision: "$Revision: 80577 $" -- --class -- POOLED_THREAD [G] -- --inherit -- THREAD -- rename -- make as thread_make -- end -- --create {THREAD_POOL} -- make -- --feature {NONE} -- Initialization -- -- make (a_thread_pool: THREAD_POOL [G]; a_semaphore: SEMAPHORE) -- -- `a_thread_pool', the pool in which this thread is managed -- -- `a_semaphore' is used for execution suspending -- do -- thread_make -- thread_pool := a_thread_pool -- semaphore := a_semaphore -- end -- --feature {NONE} -- Access -- -- thread_pool: THREAD_POOL [G] -- -- Pool manager in which this thread is pooled -- -- target: detachable G -- -- Target on which the `thread_procedure' should be applied -- -- Depending on which launch is used, target is not used -- -- thread_procedure: detachable PROCEDURE -- -- Work that should be executed by the thread -- -- semaphore: SEMAPHORE -- -- Semaphore share with all threads in a thread pool -- -- to suspend execution until more work is available -- --feature -- Access -- -- set_target (a_target: G) -- -- Sets the target on which the work should be executed -- do -- target := a_target -- end -- --feature {NONE} -- Implementation -- -- execute -- -- -- local -- done: BOOLEAN -- do -- from -- semaphore.wait -- thread_procedure := thread_pool.get_work (Current) -- until -- done -- loop -- if attached thread_procedure as l_work then -- if attached target as t then -- l_work.call ([t]) -- else -- l_work.call (Void) -- end -- end -- if thread_pool.over then -- done := True -- else -- thread_procedure := thread_pool.get_work (Current) -- if thread_procedure = Void then -- semaphore.wait -- thread_procedure := thread_pool.get_work (Current) -- end -- end -- end -- thread_pool.thread_terminated (Current) -- end -- --note -- copyright: "2011-2012, Javier Velilla and others" -- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" -- licensing_options: "http://www.eiffel.com/licensing" -- copying: "[ -- This file is part of Eiffel Software's Eiffel Development Environment. -- -- Eiffel Software's Eiffel Development Environment is free -- software; you can redistribute it and/or modify it under -- the terms of the GNU General Public License as published -- by the Free Software Foundation, version 2 of the License -- (available at the URL listed under "license" above). -- -- Eiffel Software's Eiffel Development Environment is -- distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty -- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- See the GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public -- License along with Eiffel Software's Eiffel Development -- Environment; if not, write to the Free Software Foundation, -- Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -- ]" -- 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 -- -- -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/pool/thread_pool.e b/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/pool/thread_pool.e -deleted file mode 100644 -index 02e94d9..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/concurrency/thread/pool/thread_pool.e -+++ /dev/null -@@ -1,228 +0,0 @@ --note -- description: "[ -- A thread pool manager. Manages threads up to `capacity' and queue after that, -- till threads get available again. -- ]" -- legal: "See notice at end of class." -- status: "Community Preview 1.0" -- date: "$Date: 2009-09-01 19:15:37 -0300 (mar 01 de sep de 2009) $" -- revision: "$Revision: 80577 $" -- --class -- THREAD_POOL [G] -- --inherit -- EXECUTION_ENVIRONMENT -- --create -- make -- --feature {NONE} -- Initialization -- -- make (n: like capacity) -- -- Initialize current pool with capacity `n'. -- require -- n_positive: n > 0 -- n_not_too_large: n < {INTEGER_32}.max_value.as_natural_32 -- local -- i: NATURAL -- do -- capacity := n -- create work_queue.make (n.to_integer_32) -- create work_queue_mutex.make -- create over_mutex.make -- create termination_mutex.make -- create work_semaphore.make (capacity.as_integer_32) -- from -- i := 1 -- until -- i > capacity -- loop -- work_semaphore.wait -- i := i + 1 -- end -- initialize_threads -- terminated_count := capacity -- is_over := False -- ensure -- capacity_set: capacity = n -- work_queue_set: work_queue.is_empty -- end -- -- initialize_threads -- -- Launches all threads -- local -- i: NATURAL -- thread: POOLED_THREAD [G] -- do -- from -- i := 1 -- until -- i > capacity -- loop -- create thread.make (Current, work_semaphore) -- thread.launch -- i := i + 1 -- end -- end -- --feature -- Access -- -- capacity: NATURAL -- -- Maximal number of threads allowed (queuing otherwise) -- -- queue_count: NATURAL -- -- Number of items in queue -- do -- work_queue_mutex.lock -- Result := work_queue.count.as_natural_32 -- work_queue_mutex.unlock -- end -- --feature -- Status report -- -- valid_action (a_action: PROCEDURE): BOOLEAN -- -- Is `a_action' a valid action for the current pool. -- do -- -- There should be no open operands. -- Result := a_action.valid_operands (Void) -- end -- --feature -- Basic operations -- -- add_work (work: PROCEDURE) -- -- Launches a thread with the specified argument `arg'. Reuse of thread if possible. -- require -- valid_action: valid_action (work) -- do -- work_queue_mutex.lock -- work_queue.extend (work) -- if work_queue.count <= capacity.as_integer_32 then -- -- Let one thread wake up and do the work -- work_semaphore.post -- end -- work_queue_mutex.unlock -- end -- -- over: BOOLEAN -- -- Is the thread pool being terminated? -- do -- over_mutex.lock -- Result := is_over -- over_mutex.unlock -- end -- -- thread_terminated (a_thread: POOLED_THREAD [G]) -- -- Notifies the thread pool that a thread has terminated its execution. -- do -- termination_mutex.lock -- terminated_count := terminated_count - 1 -- termination_mutex.unlock -- end -- -- get_work (requester: POOLED_THREAD [G]): detachable PROCEDURE -- -- If there is work to do, it is returned -- -- Yields Void otherwise -- do -- if not over then -- work_queue_mutex.lock -- if not work_queue.is_empty then -- Result := work_queue.item -- work_queue.remove -- end -- work_queue_mutex.unlock -- end -- end -- -- wait_for_completion -- -- Wait until there is no more work to be completed -- local -- done: BOOLEAN -- do -- from -- -- until -- done -- loop -- work_queue_mutex.lock -- done := work_queue.is_empty -- work_queue_mutex.unlock -- if not done then -- sleep (1) -- end -- end -- end -- -- terminate -- -- Terminates all the threads after their execution -- do -- over_mutex.lock -- is_over := True -- over_mutex.unlock -- from -- termination_mutex.lock -- until -- terminated_count = 0 -- loop -- work_semaphore.post -- termination_mutex.unlock -- termination_mutex.lock -- end -- termination_mutex.unlock -- end -- --feature {NONE} -- Implementation: Access -- -- work_queue: ARRAYED_QUEUE [PROCEDURE] -- -- Queue that holds unprocessed requests as agents -- -- Thread-safe access when accessor holds `queue_mutex' -- -- work_queue_mutex: MUTEX -- -- Mutex for the queue -- -- work_semaphore: SEMAPHORE -- -- Semaphore which hols the number of work to be done. -- -- Needed to wake up worker threads -- -- terminated_count: NATURAL -- -- -- -- is_over: BOOLEAN -- -- Is the thread pool being terminated? -- -- over_mutex: MUTEX -- -- Mutex for the `is_over' variable -- -- termination_mutex: MUTEX --;note -- copyright: "2011-2012, Javier Velilla, Jocelyn Fiat and others" -- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" -- licensing_options: "http://www.eiffel.com/licensing" -- copying: "[ -- This file is part of Eiffel Software's Eiffel Development Environment. -- -- Eiffel Software's Eiffel Development Environment is free -- software; you can redistribute it and/or modify it under -- the terms of the GNU General Public License as published -- by the Free Software Foundation, version 2 of the License -- (available at the URL listed under "license" above). -- -- Eiffel Software's Eiffel Development Environment is -- distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty -- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- See the GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public -- License along with Eiffel Software's Eiffel Development -- Environment; if not, write to the Free Software Foundation, -- Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -- ]" -- 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/configuration/httpd_configuration_i.e b/library/server/ewsgi/connectors/standalone/src/httpd/configuration/httpd_configuration_i.e -deleted file mode 100644 -index 8ae522a..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/configuration/httpd_configuration_i.e -+++ /dev/null -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd-safe.ecf b/library/server/ewsgi/connectors/standalone/src/httpd/httpd-safe.ecf -deleted file mode 100644 -index 440e3c1..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd-safe.ecf -+++ /dev/null -@@ -1,60 +0,0 @@ -- -- -- -- -- -- /.git$ -- /.svn$ -- /EIFGENs$ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- /concurrency$ -- /no_ssl$ -- /ssl$ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd.ecf b/library/server/ewsgi/connectors/standalone/src/httpd/httpd.ecf -deleted file mode 100644 -index 88aeaa4..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd.ecf -+++ /dev/null -@@ -1,61 +0,0 @@ -- -- -- -- -- -- /.git$ -- /.svn$ -- /EIFGENs$ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- /EIFGENs$ -- /concurrency$ -- /no_ssl$ -- /ssl$ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_connection_handler_i.e b/library/server/ewsgi/connectors/standalone/src/httpd/httpd_connection_handler_i.e -deleted file mode 100644 -index be3e51f..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_connection_handler_i.e -+++ /dev/null -@@ -1,97 +0,0 @@ --note -- description: "[ -- Interface for the incoming connection handler. -- -- Each incoming socket connection is processed by -- an implementation of HTTPD_CONNECTION_HANDLER_I. -- -- Note there are 3 implementations, one for each concurrent mode: none, thread, scoop. -- ]" -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- HTTPD_CONNECTION_HANDLER_I -- --inherit -- HTTPD_DEBUG_FACILITIES -- --feature {NONE} -- Initialization -- -- frozen make (a_server: like server) -- do -- server := a_server -- factory := separate_factory (a_server) -- initialize -- end -- -- initialize -- deferred -- end -- --feature {NONE} -- Access -- -- factory: separate HTTPD_REQUEST_HANDLER_FACTORY -- -- Request handler factory. -- -- server: separate HTTPD_SERVER_I -- -- Associated server. -- --feature {HTTPD_SERVER_I} -- Execution -- -- accept_incoming_connection (a_listening_socket: HTTPD_STREAM_SOCKET) -- -- Accept incoming connection from `a_listening_socket'. -- deferred -- end -- -- shutdown -- -- Shutdown server. -- deferred -- end -- -- wait_for_completion -- -- Wait until Current completed any pending task. -- --| Used for SCOOP synchronisation. -- deferred -- end -- --feature {HTTPD_SERVER} -- Status report -- -- is_shutdown_requested: BOOLEAN -- -- Any request to shutdown the server? -- deferred -- end -- --feature {NONE} -- Implementation -- -- log (a_message: separate READABLE_STRING_8) -- -- Log `a_message' -- do -- -- FIXME: Concurrency issue on `server' -- separate_server_log (server, a_message) -- end -- -- separate_factory (a_server: like server): like factory -- -- Separate factory from `a_server'. -- --| required by SCOOP design. -- do -- Result := a_server.factory -- end -- -- separate_server_log (a_server: like server; a_message: separate READABLE_STRING_8) -- -- Concurrent call to `a_server.log (a_message)'. -- do -- a_server.log (a_message) -- end -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_controller.e b/library/server/ewsgi/connectors/standalone/src/httpd/httpd_controller.e -deleted file mode 100644 -index f9a6667..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_controller.e -+++ /dev/null -@@ -1,28 +0,0 @@ --note -- description: "[ -- Object used to control (i.e shutdown) the server. -- Mostly needed in SCOOP concurrency mode. -- ]" -- date: "$Date$" -- revision: "$Revision$" -- --class -- HTTPD_CONTROLLER -- --feature -- Operation -- -- shutdown -- -- Request the associated server to be shutdown. -- do -- shutdown_requested := True -- end -- --feature -- Status report. -- -- shutdown_requested: BOOLEAN -- -- Shutdown requested. -- --;note -- copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others" -- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" --end -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_debug_facilities.e b/library/server/ewsgi/connectors/standalone/src/httpd/httpd_debug_facilities.e -deleted file mode 100644 -index 3182332..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_debug_facilities.e -+++ /dev/null -@@ -1,50 +0,0 @@ --note -- description: " Routines used for debug logging." -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- HTTPD_DEBUG_FACILITIES -- --feature {NONE} -- Output -- -- dbglog (m: READABLE_STRING_8) -- require -- not m.ends_with_general ("%N") -- local -- s: STRING -- do -- debug ("dbglog") -- create s.make (24) -- s.append ("[EWF/DBG] <#") -- s.append_integer (processor_id_from_object (Current)) -- s.append ("> ") -- s.append (generator) -- s.append (create {STRING}.make_filled (' ', (46 - s.count).max (0))) -- s.append (" | ") -- s.append (m) -- s.append ("%N") -- print (s) -- end -- end -- --feature -- runtime -- -- frozen processor_id_from_object (a_object: separate ANY): INTEGER_32 -- external -- "C inline use %"eif_scoop.h%"" -- alias -- "RTS_PID(eif_access($a_object))" -- end -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_logger.e b/library/server/ewsgi/connectors/standalone/src/httpd/httpd_logger.e -deleted file mode 100644 -index 057f43a..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_logger.e -+++ /dev/null -@@ -1,26 +0,0 @@ --note -- description: "Logging facilities component" -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- HTTPD_LOGGER -- --feature -- Logs -- -- log (a_message: separate READABLE_STRING_8) -- -- Log `a_message' -- 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_request_handler_factory_i.e b/library/server/ewsgi/connectors/standalone/src/httpd/httpd_request_handler_factory_i.e -deleted file mode 100644 -index 940d7a0..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_request_handler_factory_i.e -+++ /dev/null -@@ -1,26 +0,0 @@ --note -- description: "Summary description for {HTTPD_REQUEST_HANDLER_FACTORY_I}." -- author: "" -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- HTTPD_REQUEST_HANDLER_FACTORY_I -- --feature -- Factory -- -- new_handler: separate HTTPD_REQUEST_HANDLER -- 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_request_handler_i.e b/library/server/ewsgi/connectors/standalone/src/httpd/httpd_request_handler_i.e -deleted file mode 100644 -index 8eaef93..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_request_handler_i.e -+++ /dev/null -@@ -1,426 +0,0 @@ --note -- description: "HTTPD handler interface processing request." -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- HTTPD_REQUEST_HANDLER_I -- --inherit -- HTTPD_DEBUG_FACILITIES -- --feature {NONE} -- Initialization -- -- make -- do -- reset -- end -- -- reset -- do -- reset_request -- -- has_error := False -- if attached internal_client_socket as l_sock then -- l_sock.cleanup -- end -- internal_client_socket := Void -- end -- -- reset_request -- do -- version := Void -- remote_info := Void -- -- -- FIXME: optimize to just wipe_out if needed -- create method.make_empty -- create uri.make_empty -- create request_header.make_empty -- create request_header_map.make (10) -- -- is_persistent_connection_requested := False -- end -- --feature -- Status report -- -- is_connected: BOOLEAN -- -- Is handler connected to incoming request via `client_socket'? -- do -- Result := client_socket.descriptor_available -- end -- --feature -- Access -- -- internal_client_socket: detachable HTTPD_STREAM_SOCKET -- -- client_socket: HTTPD_STREAM_SOCKET -- local -- s: like internal_client_socket -- do -- s := internal_client_socket -- if s = Void then -- create s.make_empty -- internal_client_socket := s -- end -- Result := s -- end -- -- request_header: STRING -- -- Header' source -- -- request_header_map: HASH_TABLE [STRING, STRING] -- -- Contains key:value of the header -- -- method: STRING -- -- http verb -- -- uri: STRING -- -- http endpoint -- -- version: detachable STRING -- -- http_version -- --| unused for now -- -- remote_info: detachable TUPLE [addr: STRING; hostname: STRING; port: INTEGER] -- -- Information related to remote client -- -- is_persistent_connection_requested: BOOLEAN -- -- Persistent connection requested? -- -- either has "Connection: keep-alive" header, -- -- or is HTTP/1.1 and no header "Connection: close". -- -- is_http_version_1_0: BOOLEAN -- do -- Result := not attached version as v or else v.same_string ("HTTP/1.0") -- end -- -- is_http_version_1_1: BOOLEAN -- do -- Result := not attached version as v or else v.same_string ("HTTP/1.1") -- end -- -- is_http_version_2: BOOLEAN -- do -- Result := not attached version as v or else v.same_string ("HTTP/2.0") -- end -- --feature -- Settings -- -- is_verbose: BOOLEAN -- -- is_persistent_connection_supported: BOOLEAN -- -- Is persistent connection supported? -- do -- Result := {HTTPD_SERVER}.is_persistent_connection_supported -- end -- -- persistent_connection_timeout: INTEGER = 5 -- seconds -- -- Number of seconds for persistent connection timeout. -- -- Default: 5 sec. -- --feature -- Status report -- -- has_error: BOOLEAN -- -- Error occurred during `analyze_request_message' -- --feature -- Change -- -- set_is_verbose (b: BOOLEAN) -- -- Set `is_verbose' with `b'. -- do -- is_verbose := b -- ensure -- is_verbose_set: is_verbose = b -- end -- --feature -- Execution -- -- safe_execute -- -- Execute accepted incoming connection as request. -- local -- retried: BOOLEAN -- do -- if retried then -- release -- else -- if -- not has_error and then -- is_connected -- then -- execute -- end -- release -- end -- rescue -- retried := True -- retry -- end -- -- execute -- require -- is_connected: is_connected -- local -- l_socket: like client_socket -- l_exit: BOOLEAN -- n: INTEGER -- do -- l_socket := client_socket -- check -- socket_attached: l_socket /= Void -- socket_valid: l_socket.is_open_read and then l_socket.is_open_write -- end -- from -- -- Process persistent connection as long the socket is not closed. -- n := 0 -- until -- l_exit -- loop -- n := n + 1 -- -- FIXME: it seems to be called one more time, mostly to see this is done. -- execute_request -- 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_persistent_connection_requested -- reset_request -- end -- end -- -- execute_request -- require -- is_connected: is_connected -- 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 -- socket_attached: l_socket /= Void -- socket_valid: l_socket.is_open_read and then l_socket.is_open_write -- end -- if l_socket.is_closed then -- debug ("dbglog") -- dbglog (generator + ".execute_request {socket is Closed!}") -- end -- else -- debug ("dbglog") -- 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 -- l_is_ready := l_socket.ready_for_reading -- check not l_socket.is_closed end -- i := i - 1 -- end -- -- if l_is_ready then -- create l_remote_info -- if attached l_socket.peer_address as l_addr then -- l_remote_info.addr := l_addr.host_address.host_address -- l_remote_info.hostname := l_addr.host_address.host_name -- l_remote_info.port := l_addr.port -- remote_info := l_remote_info -- end -- analyze_request_message (l_socket) -- else -- has_error := True -- debug ("dbglog") -- dbglog (generator + ".execute_request socket=" + l_socket.descriptor.out + "} timeout!") -- end -- end -- -- if has_error then -- if l_is_ready then -- -- check catch_bad_incoming_connection: False end -- if is_verbose then -- log ("ERROR: invalid HTTP incoming request") -- end -- end -- else -- process_request (l_socket) -- end -- debug ("dbglog") -- dbglog (generator + ".execute_request {" + l_socket.descriptor.out + "} LEAVE") -- end -- end -- end -- -- release -- do -- reset -- end -- --feature -- Request processing -- -- process_request (a_socket: HTTPD_STREAM_SOCKET) -- -- Process request ... -- require -- no_error: not has_error -- a_uri_attached: uri /= Void -- a_method_attached: method /= Void -- a_header_map_attached: request_header_map /= Void -- a_header_text_attached: request_header /= Void -- a_socket_attached: a_socket /= Void -- deferred -- end -- --feature -- Parsing -- -- analyze_request_message (a_socket: HTTPD_STREAM_SOCKET) -- -- Analyze message extracted from `a_socket' as HTTP request -- require -- input_readable: a_socket /= Void and then a_socket.is_open_read -- local -- end_of_stream: BOOLEAN -- pos, n: INTEGER -- line: detachable STRING -- k, val: STRING -- txt: STRING -- l_is_verbose: BOOLEAN -- 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 -- txt.append (l_request_line) -- txt.append_character ('%N') -- analyze_request_line (l_request_line) -- else -- 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 -- from -- line := next_line (a_socket) -- until -- line = Void or end_of_stream -- loop -- n := line.count -- if l_is_verbose then -- log (line) -- end -- pos := line.index_of (':', 1) -- if pos > 0 then -- k := line.substring (1, pos - 1) -- if line [pos + 1].is_space then -- pos := pos + 1 -- end -- if line [n] = '%R' then -- n := n - 1 -- end -- val := line.substring (pos + 1, n) -- request_header_map.put (val, k) -- end -- txt.append (line) -- txt.append_character ('%N') -- if line.is_empty or else line [1] = '%R' then -- end_of_stream := True -- else -- line := next_line (a_socket) -- end -- end -- -- Except for HTTP/1.0, persistent connection is the default. -- is_persistent_connection_requested := True -- if is_http_version_1_0 then -- is_persistent_connection_requested := attached request_header_map.item ("Connection") as l_connection and then -- l_connection.is_case_insensitive_equal_general ("keep-alive") -- else -- -- By default HTTP:1/1 support persistent connection. -- if attached request_header_map.item ("Connection") as l_connection then -- if l_connection.is_case_insensitive_equal_general ("close") then -- is_persistent_connection_requested := False -- end -- else -- is_persistent_connection_requested := True -- end -- end -- end -- end -- -- analyze_request_line (line: STRING) -- -- Analyze `line' as a HTTP request line -- require -- valid_line: line /= Void and then not line.is_empty -- local -- n, pos, next_pos: INTEGER -- do -- if is_verbose then -- log ("%N## Parse HTTP request line ##") -- log (line) -- end -- pos := line.index_of (' ', 1) -- method := line.substring (1, pos - 1) -- next_pos := line.index_of (' ', pos + 1) -- uri := line.substring (pos + 1, next_pos - 1) -- n := line.count -- if line[n] = '%R' then -- n := n - 1 -- end -- version := line.substring (next_pos + 1, n) -- has_error := method.is_empty -- end -- -- next_line (a_socket: HTTPD_STREAM_SOCKET): detachable STRING -- -- Next line fetched from `a_socket' is available. -- require -- is_readable: a_socket.is_open_read -- local -- retried: BOOLEAN -- do -- if retried then -- Result := Void -- elseif a_socket.socket_ok then -- a_socket.read_line_thread_aware -- Result := a_socket.last_string -- end -- rescue -- retried := True -- retry -- end -- --feature -- Output -- -- logger: detachable HTTPD_LOGGER -- -- set_logger (a_logger: like logger) -- -- Set `logger' with `a_logger'. -- do -- logger := a_logger -- ensure -- logger_set: logger = a_logger -- end -- -- log (m: STRING) -- -- Log message `m'. -- do -- if attached logger as l_logger then -- l_logger.log (m) -- else -- io.put_string (m + "%N") -- end -- end -- --invariant -- request_header_attached: request_header /= Void -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_server_i.e b/library/server/ewsgi/connectors/standalone/src/httpd/httpd_server_i.e -deleted file mode 100644 -index d3c236d..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_server_i.e -+++ /dev/null -@@ -1,354 +0,0 @@ --note -- description: "HTTPD server interface" -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- HTTPD_SERVER_I -- --inherit -- HTTPD_DEBUG_FACILITIES -- -- HTTPD_LOGGER -- --feature {NONE} -- Initialization -- -- make (a_factory: like factory) -- -- Create current httpd server with `a_factory' of connection handlers. -- -- `a_factory': connection handler builder -- require -- a_factory_is_separated: {PLATFORM}.is_scoop_capable implies not attached {HTTPD_REQUEST_HANDLER_FACTORY} a_factory -- do -- make_configured (create {like configuration}.make, a_factory) -- end -- -- make_configured (a_cfg: like configuration; a_factory: like factory) -- -- `a_cfg': server configuration -- -- `a_factory': connection handler builder -- do -- configuration := a_cfg -- factory := a_factory -- -- build_controller -- -- initialize -- end -- -- build_controller -- -- Build `controller'. -- do -- create controller -- end -- -- initialize -- -- Initialize Current server. -- do -- is_shutdown_requested := False -- end -- --feature -- Access -- -- is_verbose: BOOLEAN -- -- Is verbose for output messages. -- -- configuration: HTTPD_CONFIGURATION -- -- Associated server configuration. -- -- controller: separate HTTPD_CONTROLLER -- -- factory: separate HTTPD_REQUEST_HANDLER_FACTORY -- -- is_persistent_connection_supported: BOOLEAN = True -- -- Is persistent connection supported? -- --feature -- Callbacks -- -- observer: detachable separate HTTPD_SERVER_OBSERVER -- -- set_observer (obs: like observer) -- -- Set `observer' to `obs'. -- do -- observer := obs -- end -- --feature -- Access: listening -- -- port: INTEGER -- -- Effective listening port. -- --| If 0 then it is not launched successfully! -- --feature -- Status: listening -- -- is_launched: BOOLEAN -- -- Server launched and listening on `port' -- -- is_terminated: BOOLEAN -- -- Is terminated? -- -- is_shutdown_requested: BOOLEAN -- -- Set true to stop accept loop -- --feature {NONE} -- Access: server -- -- request_counter: INTEGER -- -- request counter, incremented for each new incoming connection. -- --feature -- Execution -- -- launch -- do -- apply_configuration -- is_terminated := False -- if is_verbose then -- log ("%N%NStarting Web Application Server (port=" + configuration.http_server_port.out + "):%N") -- end -- is_shutdown_requested := False -- listen -- is_terminated := True -- on_terminated -- end -- -- shutdown_server -- do -- debug ("dbglog") -- dbglog ("Shutdown requested") -- end -- is_shutdown_requested := True -- controller_shutdown (controller) -- end -- -- controller_shutdown (ctl: attached like controller) -- do -- ctl.shutdown -- end -- --feature -- Listening -- -- listen -- -- -- -- Creates a socket and connects to the http server. -- -- `a_server': The main server object -- local -- l_listening_socket: detachable HTTPD_STREAM_SOCKET -- l_http_port: INTEGER -- l_connection_handler: HTTPD_CONNECTION_HANDLER -- do -- is_terminated := False -- is_launched := False -- port := 0 -- is_shutdown_requested := False -- l_http_port := configuration.http_server_port -- -- if -- attached configuration.http_server_name as l_servername and then -- attached (create {INET_ADDRESS_FACTORY}).create_from_name (l_servername) as l_addr -- then -- l_listening_socket := new_listening_socket (l_addr, l_http_port) -- else -- l_listening_socket := new_listening_socket (Void, l_http_port) -- end -- -- if not l_listening_socket.is_bound then -- if is_verbose then -- log ("Socket could not be bound on port " + l_http_port.out) -- end -- else -- l_http_port := l_listening_socket.port -- create l_connection_handler.make (Current) -- from -- 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 + "/") -- else -- log ("%NHTTP Connection Server ready on port " + l_http_port.out +" : http://localhost:" + l_http_port.out + "/") -- end -- end -- on_launched (l_http_port) -- until -- is_shutdown_requested -- loop -- request_counter := request_counter + 1 -- if is_verbose then -- log ("#" + request_counter.out + "# Waiting connection...(listening socket:" + l_listening_socket.descriptor.out + ")") -- end -- debug ("dbglog") -- dbglog (generator + ".before process_waiting_incoming_connection") -- end -- l_connection_handler.accept_incoming_connection (l_listening_socket) -- debug ("dbglog") -- dbglog (generator + ".after process_waiting_incoming_connection") -- end -- -- update_is_shutdown_requested (l_connection_handler) -- end -- wait_for_connection_handler_completion (l_connection_handler) -- l_listening_socket.cleanup -- check -- socket_is_closed: l_listening_socket.is_closed -- end -- end -- if is_launched then -- on_stopped -- end -- if is_verbose then -- log ("HTTP Connection Server ends.") -- end -- rescue -- log ("HTTP Connection Server shutdown due to exception. Please relaunch manually.") -- -- if l_listening_socket /= Void then -- l_listening_socket.cleanup -- check -- listening_socket_is_closed: l_listening_socket.is_closed -- end -- end -- if is_launched then -- on_stopped -- end -- is_shutdown_requested := True -- retry -- end -- --feature {NONE} -- Factory -- -- new_listening_socket (a_addr: detachable INET_ADDRESS; a_http_port: INTEGER): HTTPD_STREAM_SOCKET -- do -- if a_addr /= Void then -- create Result.make_server_by_address_and_port (a_addr, a_http_port) -- else -- create Result.make_server_by_port (a_http_port) -- end -- end -- --feature {NONE} -- Helpers -- -- wait_for_connection_handler_completion (h: HTTPD_CONNECTION_HANDLER) -- do -- h.wait_for_completion -- debug ("dbglog") -- dbglog ("Shutdown ready from connection_handler point of view") -- end -- end -- -- update_is_shutdown_requested (a_connection_handler: HTTPD_CONNECTION_HANDLER) -- do -- is_shutdown_requested := is_shutdown_requested or shutdown_requested (controller) -- if is_shutdown_requested then -- a_connection_handler.shutdown -- end -- end -- -- shutdown_requested (a_controller: separate HTTPD_CONTROLLER): BOOLEAN -- -- Shutdown requested on concurrent `a_controller'? -- do -- Result := a_controller.shutdown_requested -- end -- --feature -- Event -- -- on_launched (a_port: INTEGER) -- -- Server launched using port `a_port' -- require -- not_launched: not is_launched -- do -- is_launched := True -- port := a_port -- if attached observer as obs then -- observer_on_launched (obs, a_port) -- end -- ensure -- is_launched: is_launched -- end -- -- on_stopped -- -- Server stopped -- require -- is_launched: is_launched -- do -- if attached observer as obs then -- observer_on_stopped (obs) -- end -- end -- -- on_terminated -- -- Server terminated -- require -- is_terminated -- do -- if is_terminated and is_verbose then -- log ("%N%NTerminating Web Application Server (port="+ port.out +"):%N") -- end -- if attached output as o then -- o.flush -- o.close -- end -- if attached observer as obs then -- observer_on_terminated (obs) -- end -- end -- --feature {NONE} -- Separate event -- -- observer_on_launched (obs: attached like observer; a_port: INTEGER) -- do -- obs.on_launched (a_port) -- end -- -- observer_on_stopped (obs: attached like observer) -- do -- obs.on_stopped -- end -- -- observer_on_terminated (obs: attached like observer) -- do -- obs.on_terminated -- end -- --feature -- Configuration change -- -- apply_configuration -- require -- is_not_launched: not is_launched -- do -- is_verbose := configuration.is_verbose -- end -- --feature -- Output -- -- output: detachable FILE -- -- set_log_output (f: FILE) -- -- Set `output' to `f'. -- do -- output := f -- ensure -- output_set: output = f -- end -- -- log (a_message: separate READABLE_STRING_8) -- -- Log `a_message'. -- local -- m: STRING -- do -- create m.make_from_separate (a_message) -- if attached output as o then -- o.put_string (m) -- o.put_new_line -- else -- io.error.put_string (m) -- io.error.put_new_line -- end -- end -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_server_observer.e b/library/server/ewsgi/connectors/standalone/src/httpd/httpd_server_observer.e -deleted file mode 100644 -index 18a5998..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/httpd_server_observer.e -+++ /dev/null -@@ -1,27 +0,0 @@ --note -- description: "Summary description for {HTTPD_SERVER_OBSERVER}." -- date: "$Date$" -- revision: "$Revision$" -- --deferred class -- HTTPD_SERVER_OBSERVER -- --feature -- Event -- -- on_launched (a_port: INTEGER) -- -- Associated server launched listening on port `a_port'. -- deferred -- end -- -- on_stopped -- -- Associated server stopped. -- --| the server may restart itself after being rescued. -- deferred -- end -- -- on_terminated -- -- Associated server terminated. -- deferred -- end -- --end -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/network/httpd_stream_socket.e b/library/server/ewsgi/connectors/standalone/src/httpd/network/httpd_stream_socket.e -deleted file mode 100644 -index 4f4f115..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/network/httpd_stream_socket.e -+++ /dev/null -@@ -1,307 +0,0 @@ --note -- description: "[ -- Summary description for {HTTPD_STREAM_SOCKET} -- that can be used for http or https connection. -- ]" -- date: "$Date$" -- revision: "$Revision$" -- --class -- HTTPD_STREAM_SOCKET -- --create -- make_server_by_address_and_port, -- make_server_by_port, -- make_from_separate, -- make_empty -- --create {HTTPD_STREAM_SOCKET} -- make -- --feature {NONE} -- Initialization -- -- make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER) -- do -- create {TCP_STREAM_SOCKET} socket.make_server_by_address_and_port (an_address, a_port) -- end -- -- make_server_by_port (a_port: INTEGER) -- do -- create {TCP_STREAM_SOCKET} socket.make_server_by_port (a_port) -- end -- -- make_from_separate (s: separate HTTPD_STREAM_SOCKET) -- require -- descriptor_available: s.descriptor_available -- do -- create {TCP_STREAM_SOCKET} socket.make_from_separate (s.socket) -- end -- -- make_empty -- do -- create {TCP_STREAM_SOCKET} socket.make_empty -- end -- -- retrieve_socket (s: HTTPD_STREAM_SOCKET): INTEGER -- do -- Result := s.socket.descriptor -- end -- --feature -- Change -- -- set_timeout (n: INTEGER) -- do -- if attached {NETWORK_STREAM_SOCKET} socket as l_socket then -- l_socket.set_timeout (n) -- end -- end -- -- set_connect_timeout (n: INTEGER) -- do -- if attached {NETWORK_STREAM_SOCKET} socket as l_socket then -- l_socket.set_connect_timeout (n) -- end -- end -- -- set_accept_timeout (n: INTEGER) -- do -- if attached {NETWORK_STREAM_SOCKET} socket as l_socket then -- l_socket.set_accept_timeout (n) -- end -- end -- --feature -- Access -- -- last_string: STRING -- do -- Result := socket.last_string -- end -- -- last_character: CHARACTER -- do -- Result := socket.last_character -- end -- -- peer_address: detachable NETWORK_SOCKET_ADDRESS -- -- Peer address of socket -- do -- if attached {NETWORK_SOCKET_ADDRESS} socket.peer_address as l_peer_address then -- Result := l_peer_address -- end -- end -- --feature -- Input -- -- read_line_thread_aware -- do -- socket.read_line_thread_aware -- end -- -- read_stream_thread_aware (nb: INTEGER) -- do -- socket.read_stream_thread_aware (nb) -- end -- -- read_stream (nb: INTEGER) -- do -- socket.read_stream (nb) -- end -- -- read_character -- do -- socket.read_character -- end -- -- bytes_read: INTEGER -- do -- Result := socket.bytes_read -- end -- --feature -- Output -- -- send_message (a_msg: STRING) -- do -- put_string (a_msg) -- end -- -- put_readable_string_8 (s: READABLE_STRING_8) -- -- Write readable string `s' to socket. -- do -- if attached {TCP_STREAM_SOCKET} socket as l_tcp_stream_socket then -- l_tcp_stream_socket.put_readable_string_8 (s) -- else -- put_string (s) -- end -- end -- -- put_string (s: STRING) -- do -- socket.put_string (s) -- end -- -- put_character (c: CHARACTER) -- do -- socket.put_character (c) -- end -- --feature -- Status Report -- -- descriptor_available: BOOLEAN -- -- Is descriptor available? -- do -- Result := socket.descriptor_available -- end -- -- descriptor: INTEGER -- do -- Result := socket.descriptor -- end -- -- port: INTEGER -- do -- if attached {TCP_STREAM_SOCKET} socket as l_socket then -- Result := l_socket.port -- end -- end -- -- is_blocking: BOOLEAN -- do -- Result := socket.is_blocking -- end -- -- is_bound: BOOLEAN -- do -- if attached {TCP_STREAM_SOCKET} socket as l_socket then -- Result := l_socket.is_bound -- end -- end -- -- is_created: BOOLEAN -- do -- if attached {NETWORK_SOCKET} socket as l_socket then -- Result := l_socket.is_created -- end -- end -- -- socket_ok: BOOLEAN -- do -- Result := socket.socket_ok -- end -- -- is_open_read: BOOLEAN -- do -- Result := socket.is_open_read -- end -- -- is_open_write: BOOLEAN -- do -- Result := socket.is_open_write -- end -- -- is_closed: BOOLEAN -- do -- Result := socket.is_closed -- end -- -- is_readable: BOOLEAN -- do -- Result := socket.is_readable -- end -- -- cleanup -- do -- socket.cleanup -- end -- -- ready_for_writing: BOOLEAN -- do -- if attached {TCP_STREAM_SOCKET} socket as l_socket then -- Result := l_socket.ready_for_writing -- end -- end -- -- listen (a_queue: INTEGER) -- do -- socket.listen (a_queue) -- end -- -- accept -- do -- socket.accept -- end -- -- accept_to (other: separate HTTPD_STREAM_SOCKET) -- -- Accept a new connection on listen socket. -- -- Socket of accepted connection is available in `other'. -- do -- if -- attached {NETWORK_STREAM_SOCKET} socket as l_socket and then -- attached {separate NETWORK_STREAM_SOCKET} other.socket as l_other_socket -- then -- l_socket.accept_to (l_other_socket) -- end -- end -- -- set_blocking -- do -- socket.set_blocking -- end -- -- set_non_blocking -- do -- socket.set_non_blocking -- end -- -- readable: BOOLEAN -- do -- Result := socket.readable -- end -- -- ready_for_reading: BOOLEAN -- do -- if attached {TCP_STREAM_SOCKET} socket as l_socket then -- Result := l_socket.ready_for_reading -- end -- end -- -- try_ready_for_reading: BOOLEAN -- do -- if attached {TCP_STREAM_SOCKET} socket as l_socket then -- Result := l_socket.try_ready_for_reading -- end -- end -- -- accepted: detachable HTTPD_STREAM_SOCKET -- do -- if attached {NETWORK_STREAM_SOCKET} socket.accepted as l_accepted then -- create Result.make (l_accepted) -- end -- end -- --feature {HTTPD_STREAM_SOCKET} -- Implementation -- -- make (a_socket: STREAM_SOCKET) -- do -- socket := a_socket -- end -- -- socket: STREAM_SOCKET -- -- network_stream_socket: detachable NETWORK_STREAM_SOCKET -- do -- if attached {NETWORK_STREAM_SOCKET} socket as s then -- Result := s -- end -- end -- --;note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/network/tcp_stream_socket.e b/library/server/ewsgi/connectors/standalone/src/httpd/network/tcp_stream_socket.e -deleted file mode 100644 -index 2e88f19..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/network/tcp_stream_socket.e -+++ /dev/null -@@ -1,94 +0,0 @@ --note -- description: "Summary description for {TCP_STREAM_SOCKET}." -- date: "$Date$" -- revision: "$Revision$" -- --class -- TCP_STREAM_SOCKET -- --inherit -- NETWORK_STREAM_SOCKET -- redefine -- make -- end -- --create -- make_server_by_address_and_port, -- make_server_by_port, -- make_from_separate, -- make_empty -- --create {NETWORK_STREAM_SOCKET} -- make_from_descriptor_and_address -- --feature {NONE} -- Initialization -- -- make -- -- Create a network stream socket. -- do -- Precursor -- debug -- set_reuse_address -- end -- end -- -- make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER) -- -- Create server socket on `an_address' and `a_port'. -- require -- valid_port: a_port >= 0 -- do -- make -- create address.make_from_address_and_port (an_address, a_port) -- bind -- end -- -- make_from_separate (s: separate STREAM_SOCKET) -- require -- descriptor_available: s.descriptor_available -- do -- create_from_descriptor (s.descriptor) -- end -- --feature -- Basic operation -- -- send_message (a_msg: STRING) -- do -- put_string (a_msg) -- end -- --feature -- Output -- -- put_readable_string_8 (s: READABLE_STRING_8) -- -- Write readable string `s' to socket. -- local -- ext: C_STRING -- do -- create ext.make (s) -- put_managed_pointer (ext.managed_data, 0, s.count) -- end -- --feature -- Status report -- -- try_ready_for_reading: BOOLEAN -- -- Is data available for reading from the socket right now? -- require -- socket_exists: exists -- local -- retval: INTEGER -- do -- retval := c_select_poll_with_timeout (descriptor, True, 0) -- Result := (retval > 0) -- end -- --note -- copyright: "2011-2015, 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/no_ssl/httpd_configuration.e b/library/server/ewsgi/connectors/standalone/src/httpd/no_ssl/httpd_configuration.e -deleted file mode 100644 -index 65ae18c..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/no_ssl/httpd_configuration.e -+++ /dev/null -@@ -1,66 +0,0 @@ --note -- description: "Standalone server configuration (ssl NOT supported)." -- date: "$Date$" -- revision: "$Revision$" -- --class -- HTTPD_CONFIGURATION -- --inherit -- HTTPD_CONFIGURATION_I -- --create -- make -- --feature -- Status -- -- Server_details: STRING_8 = "Server: Standalone Eiffel Server" -- -- has_ssl_support: BOOLEAN = False -- -- Precursor -- --feature -- SSL Helpers -- -- set_ssl_protocol_to_ssl_2_or_3 -- -- Set `ssl_protocol' with `Ssl_23'. -- do -- -- Ignored -- end -- -- -- set_ssl_protocol_to_tls_1_0 -- -- Set `ssl_protocol' with `Tls_1_0'. -- do -- -- Ignored -- end -- -- set_ssl_protocol_to_tls_1_1 -- -- Set `ssl_protocol' with `Tls_1_1'. -- do -- -- Ignored -- end -- -- set_ssl_protocol_to_tls_1_2 -- -- Set `ssl_protocol' with `Tls_1_2'. -- do -- -- Ignored -- end -- -- set_ssl_protocol_to_dtls_1_0 -- -- Set `ssl_protocol' with `Dtls_1_0'. -- do -- -- Ignored -- 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/no_ssl/httpd_server.e b/library/server/ewsgi/connectors/standalone/src/httpd/no_ssl/httpd_server.e -deleted file mode 100644 -index 8787e1f..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/no_ssl/httpd_server.e -+++ /dev/null -@@ -1,27 +0,0 @@ --note -- description: "[ -- httpd server -- ]" -- date: "$Date$" -- revision: "$Revision$" -- --class -- HTTPD_SERVER -- --inherit -- HTTPD_SERVER_I -- --create -- make -- --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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/ssl/httpd_configuration.e b/library/server/ewsgi/connectors/standalone/src/httpd/ssl/httpd_configuration.e -deleted file mode 100644 -index b7eba79..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/ssl/httpd_configuration.e -+++ /dev/null -@@ -1,79 +0,0 @@ --note -- description: "Standalone server configuration (ssl supported)." -- date: "$Date$" -- revision: "$Revision$" -- --class -- HTTPD_CONFIGURATION -- --inherit -- HTTPD_CONFIGURATION_I -- redefine -- make -- end -- --create -- make -- --feature {NONE} -- Initialization -- -- make -- -- Create a new instance and set ssl protocol to tls_1_2. -- do -- Precursor -- set_ssl_protocol_to_tls_1_2 -- ensure then -- ssl_protocol_set: ssl_protocol = {SSL_PROTOCOL}.tls_1_2 -- end -- --feature -- Access -- -- Server_details: STRING_8 = "Server: Standalone Eiffel Server (https)" -- -- has_ssl_support: BOOLEAN = True -- -- Precursor -- --feature -- SSL Helpers -- -- set_ssl_protocol_to_ssl_2_or_3 -- -- Set `ssl_protocol' with `Ssl_23'. -- do -- set_ssl_protocol ({SSL_PROTOCOL}.Ssl_23) -- end -- -- set_ssl_protocol_to_tls_1_0 -- -- Set `ssl_protocol' with `Tls_1_0'. -- do -- set_ssl_protocol ({SSL_PROTOCOL}.Tls_1_0) -- end -- -- set_ssl_protocol_to_tls_1_1 -- -- Set `ssl_protocol' with `Tls_1_1'. -- do -- set_ssl_protocol ({SSL_PROTOCOL}.Tls_1_1) -- end -- -- set_ssl_protocol_to_tls_1_2 -- -- Set `ssl_protocol' with `Tls_1_2'. -- do -- set_ssl_protocol ({SSL_PROTOCOL}.Tls_1_2) -- end -- -- set_ssl_protocol_to_dtls_1_0 -- -- Set `ssl_protocol' with `Dtls_1_0'. -- do -- set_ssl_protocol ({SSL_PROTOCOL}.Dtls_1_0) -- 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/ssl/httpd_server.e b/library/server/ewsgi/connectors/standalone/src/httpd/ssl/httpd_server.e -deleted file mode 100644 -index 4045aa2..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/ssl/httpd_server.e -+++ /dev/null -@@ -1,35 +0,0 @@ --note -- description: "[ -- SSL enabled server -- ]" -- date: "$Date$" -- revision: "$Revision$" -- --class -- HTTPD_SERVER -- --inherit -- HTTPD_SERVER_I -- redefine -- new_listening_socket -- end -- --create -- make -- --feature {NONE} -- Factory -- -- new_listening_socket (a_addr: detachable INET_ADDRESS; a_http_port: INTEGER): HTTPD_STREAM_SOCKET -- do -- if configuration.is_secure then -- if a_addr /= Void then -- create {HTTPD_STREAM_SSL_SOCKET} Result.make_ssl_server_by_address_and_port (a_addr, a_http_port, configuration.ssl_protocol, configuration.ca_crt, configuration.ca_key) -- else -- create {HTTPD_STREAM_SSL_SOCKET} Result.make_ssl_server_by_port (a_http_port, configuration.ssl_protocol, configuration.ca_crt, configuration.ca_key) -- end -- else -- Result := Precursor (a_addr, a_http_port) -- end -- end -- --end -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/ssl/httpd_stream_ssl_socket.e b/library/server/ewsgi/connectors/standalone/src/httpd/ssl/httpd_stream_ssl_socket.e -deleted file mode 100644 -index e1f25ca..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/ssl/httpd_stream_ssl_socket.e -+++ /dev/null -@@ -1,139 +0,0 @@ --note -- description: "[ -- Summary description for {HTTPD_STREAM_SSL_SOCKET} -- that can be used for http or https connection. -- ]" -- date: "$Date$" -- revision: "$Revision$" -- --class -- HTTPD_STREAM_SSL_SOCKET -- --inherit -- HTTPD_STREAM_SOCKET -- redefine -- port, -- is_bound, -- ready_for_writing, -- ready_for_reading, -- try_ready_for_reading, -- put_readable_string_8 -- end -- --create -- make_ssl_server_by_address_and_port, make_ssl_server_by_port, -- make_server_by_address_and_port, make_server_by_port -- --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) -- 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) -- end -- -- make_ssl_server_by_port (a_port: INTEGER; a_ssl_protocol: NATURAL; a_crt: STRING; a_key: STRING) -- 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) -- end -- --feature -- Output -- -- put_readable_string_8 (s: READABLE_STRING_8) -- -- -- do -- if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then -- l_ssl_socket.put_readable_string_8 (s) -- else -- Precursor (s) -- end -- end -- --feature -- Status Report -- -- port: INTEGER -- -- -- do -- if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then -- Result := l_ssl_socket.port -- else -- Result := Precursor -- end -- end -- -- is_bound: BOOLEAN -- -- -- do -- if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then -- Result := l_ssl_socket.is_bound -- else -- Result := Precursor -- end -- end -- -- ready_for_writing: BOOLEAN -- -- -- do -- if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then -- Result := l_ssl_socket.ready_for_writing -- else -- Result := Precursor -- end -- end -- -- ready_for_reading: BOOLEAN -- -- -- do -- if attached {SSL_TCP_STREAM_SOCKET} socket as l_ssl_socket then -- Result := l_ssl_socket.ready_for_reading -- else -- Result := Precursor -- end -- end -- -- try_ready_for_reading: BOOLEAN -- do -- if attached {SSL_TCP_STREAM_SOCKET} socket as l_socket then -- Result := l_socket.try_ready_for_reading -- else -- Result := Precursor -- end -- end -- --feature {HTTPD_STREAM_SOCKET} -- Implementation -- -- set_certificates (a_crt: STRING; a_key: STRING) -- local -- a_file_name: FILE_NAME -- 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) -- end -- 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/httpd/ssl/ssl_tcp_stream_socket.e b/library/server/ewsgi/connectors/standalone/src/httpd/ssl/ssl_tcp_stream_socket.e -deleted file mode 100644 -index f1043ad..0000000 ---- a/library/server/ewsgi/connectors/standalone/src/httpd/ssl/ssl_tcp_stream_socket.e -+++ /dev/null -@@ -1,72 +0,0 @@ --note -- description: "SSL tcp stream socket." -- date: "$Date$" -- revision: "$Revision$" -- --class -- SSL_TCP_STREAM_SOCKET -- --inherit -- -- SSL_NETWORK_STREAM_SOCKET -- --create -- make_server_by_address_and_port, make_server_by_port, -- make_empty -- --create {SSL_NETWORK_STREAM_SOCKET} -- make_from_descriptor_and_address -- --feature {NONE} -- Initialization -- -- make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER) -- -- Create server socket on `an_address' and `a_port'. -- require -- valid_port: a_port >= 0 -- do -- make -- create address.make_from_address_and_port (an_address, a_port) -- bind -- end -- --feature -- Basic operation -- -- send_message (a_msg: STRING) -- do -- put_string (a_msg) -- end -- --feature -- Output -- -- put_readable_string_8 (s: READABLE_STRING_8) -- -- Write readable string `s' to socket. -- local -- ext: C_STRING -- do -- create ext.make (s) -- put_managed_pointer (ext.managed_data, 0, s.count) -- end -- --feature -- Status report -- -- try_ready_for_reading: BOOLEAN -- -- Is data available for reading from the socket right now? -- require -- socket_exists: exists -- local -- retval: INTEGER -- do -- retval := c_select_poll_with_timeout (descriptor, True, 0) -- Result := (retval > 0) -- end -- --feature {NONE}-- Implementation -- -- -- -- --note -- copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others" -- license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" -- --end -diff --git a/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler.e b/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler.e -index 3abd522..4ff9ac8 100644 ---- a/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler.e -+++ b/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler_factory.e b/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler_factory.e -index 48ea569..5dc7c4b 100644 ---- a/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler_factory.e -+++ b/library/server/ewsgi/connectors/standalone/src/implementation/wgi_httpd_request_handler_factory.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_connector.e b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_connector.e -index 9c35e71..0d227df 100644 ---- a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_connector.e -+++ b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_connector.e -@@ -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 fac -+ request_handler_factory := fac - create server.make (fac) -- create observer -+ create 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 -diff --git a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_connector_exporter.e b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_connector_exporter.e -new file mode 100644 -index 0000000..bbfa7ca ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_connector_exporter.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_constants.e b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_constants.e -new file mode 100644 -index 0000000..dd5914c ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_constants.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_httpd_logger_constants.e b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_httpd_logger_constants.e -new file mode 100644 -index 0000000..c0e7502 ---- /dev/null -+++ b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_httpd_logger_constants.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_input_stream.e b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_input_stream.e -index 2013ad6..1cf333a 100644 ---- a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_input_stream.e -+++ b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_input_stream.e -@@ -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 -diff --git a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_response_stream.e b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_response_stream.e -index ad19d07..40a65e5 100644 ---- a/library/server/ewsgi/connectors/standalone/src/wgi_standalone_response_stream.e -+++ b/library/server/ewsgi/connectors/standalone/src/wgi_standalone_response_stream.e -@@ -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) -diff --git a/library/server/ewsgi/connectors/standalone/standalone-safe.ecf b/library/server/ewsgi/connectors/standalone/standalone-safe.ecf -index cbb239d..84514c6 100644 ---- a/library/server/ewsgi/connectors/standalone/standalone-safe.ecf -+++ b/library/server/ewsgi/connectors/standalone/standalone-safe.ecf -@@ -16,7 +16,7 @@ - - - -- -+ - - -diff --git a/library/server/ewsgi/connectors/standalone/standalone.ecf b/library/server/ewsgi/connectors/standalone/standalone.ecf -index 4fd3418..89c4189 100644 ---- a/library/server/ewsgi/connectors/standalone/standalone.ecf -+++ b/library/server/ewsgi/connectors/standalone/standalone.ecf -@@ -15,7 +15,7 @@ - - - -- -+ - - -diff --git a/library/server/ewsgi/connectors/standalone/test_standalone-safe.ecf b/library/server/ewsgi/connectors/standalone/test_standalone-safe.ecf -index 361d9d8..c0e72fa 100644 ---- a/library/server/ewsgi/connectors/standalone/test_standalone-safe.ecf -+++ b/library/server/ewsgi/connectors/standalone/test_standalone-safe.ecf -@@ -10,12 +10,11 @@ - - - -- -+ - - -- - - - -@@ -27,4 +26,10 @@ - - - -+ -+ -+ -+ -+ -+ - -diff --git a/library/server/libfcgi/libfcgi-safe.ecf b/library/server/libfcgi/libfcgi-safe.ecf -index 0ae6aed..6958b48 100644 ---- a/library/server/libfcgi/libfcgi-safe.ecf -+++ b/library/server/libfcgi/libfcgi-safe.ecf -@@ -24,11 +24,11 @@ - - - -- -+ - - - -- -+ - - - -diff --git a/library/server/libfcgi/libfcgi.ecf b/library/server/libfcgi/libfcgi.ecf -index 1b0dbdc..9216b61 100644 ---- a/library/server/libfcgi/libfcgi.ecf -+++ b/library/server/libfcgi/libfcgi.ecf -@@ -25,11 +25,11 @@ - - - -- -+ - - - -- -+ - - - -diff --git a/library/server/wsf/connector/standalone/wsf_standalone_service_launcher.e b/library/server/wsf/connector/standalone/wsf_standalone_service_launcher.e -index 006a23e..e416960 100644 ---- a/library/server/wsf/connector/standalone/wsf_standalone_service_launcher.e -+++ b/library/server/wsf/connector/standalone/wsf_standalone_service_launcher.e -@@ -2,14 +2,27 @@ note - description: "[ - Component to launch the service using the default connector - -- Eiffel Web httpd for this class -+ EiffelWeb httpd for this class - -+ The httpd default connector support options: -+ verbose: to display verbose output -+ port: numeric such as 8099 (or equivalent string as "8099") -+ base: base_url (very specific to standalone server) -+ -+ max_concurrent_connections: set one, for single threaded behavior -+ max_tcp_clients: max number of open tcp connection -+ -+ socket_timeout: connection timeout -+ socket_recv_timeout: read data timeout -+ -+ keep_alive_timeout: amount of time the server will wait for subsequent -+ requests on a persistent connection, -+ max_keep_alive_requests: number of requests allowed on a persistent connection, -+ -+ ssl_enabled: set to True for https support. -+ ssl_ca_crt: path to the certificat crt file (relevant when ssl_enabled is True) -+ ssl_ca_key: path to the certificat key file (relevant when ssl_enabled is True) - -- The httpd default connector support options: -- port: numeric such as 8099 (or equivalent string as "8099") -- base: base_url (very specific to standalone server) -- verbose: to display verbose output, useful for standalone connector -- force_single_threaded: use only one thread, useful for standalone connector - - check WSF_SERVICE_LAUNCHER for more documentation - ]" -@@ -25,6 +38,8 @@ inherit - launchable - end - -+ WGI_STANDALONE_HTTPD_LOGGER_CONSTANTS -+ - create - make, - make_and_launch -@@ -34,37 +49,77 @@ feature {NONE} -- Initialization - initialize - local - conn: like connector -+ s: READABLE_STRING_GENERAL - do - create on_launched_actions - create on_stopped_actions - -- port_number := 80 --| Default, but quite often, this port is already used ... -+ port_number := {WGI_STANDALONE_CONSTANTS}.default_http_server_port --| Default, but quite often, this port is already used ... -+ max_concurrent_connections := {WGI_STANDALONE_CONSTANTS}.default_max_concurrent_connections -+ max_tcp_clients := {WGI_STANDALONE_CONSTANTS}.default_max_tcp_clients -+ socket_timeout := {WGI_STANDALONE_CONSTANTS}.default_socket_timeout -- seconds -+ socket_recv_timeout := {WGI_STANDALONE_CONSTANTS}.default_socket_recv_timeout -- seconds -+ keep_alive_timeout := {WGI_STANDALONE_CONSTANTS}.default_keep_alive_timeout -- seconds. -+ max_keep_alive_requests := {WGI_STANDALONE_CONSTANTS}.default_max_keep_alive_requests -+ verbose := False -+ verbose_level := notice_level -+ - base_url := "" - - if attached options as opts then - if attached {READABLE_STRING_GENERAL} opts.option ("server_name") as l_server_name then - server_name := l_server_name.to_string_8 - end -- if attached {INTEGER} opts.option ("port") as l_port then -- port_number := l_port -- elseif -- attached {READABLE_STRING_GENERAL} opts.option ("port") as l_port_str and then -- l_port_str.is_integer -- then -- port_number := l_port_str.as_string_8.to_integer -- end - if attached {READABLE_STRING_GENERAL} opts.option ("base") as l_base_str then - base_url := l_base_str.as_string_8 - end -- if attached {BOOLEAN} opts.option ("force_single_threaded") as l_single_threaded then -- single_threaded := l_single_threaded -- elseif attached {READABLE_STRING_GENERAL} opts.option ("force_single_threaded") as l_single_threaded_str then -- single_threaded := l_single_threaded_str.as_lower.same_string ("true") -+ -+ verbose := opts.option_boolean_value ("verbose", verbose) -+ -- See `{HTTPD_REQUEST_HANDLER_I}.*_verbose_level` -+ -+ if opts.has_integer_option ("verbose_level") then -+ verbose_level := opts.option_integer_value ("verbose_level", verbose_level) -+ elseif attached {READABLE_STRING_GENERAL} opts.option ("verbose_level") as s_verbose_level then -+ verbose_level := 0 -- Reset -+ across -+ s_verbose_level.split ('+') as ic -+ loop -+ s := ic.item -+ if s.is_case_insensitive_equal ("alert") then -+ verbose_level := verbose_level | alert_level -+ elseif s.is_case_insensitive_equal ("critical") then -+ verbose_level := verbose_level | critical_level -+ elseif s.is_case_insensitive_equal ("error") then -+ verbose_level := verbose_level | error_level -+ elseif s.is_case_insensitive_equal ("warning") then -+ verbose_level := verbose_level | warning_level -+ elseif s.is_case_insensitive_equal ("notice") then -+ verbose_level := verbose_level | notice_level -+ elseif s.is_case_insensitive_equal ("information") then -+ verbose_level := verbose_level | information_level -+ elseif s.is_case_insensitive_equal ("debug") then -+ verbose_level := verbose_level | debug_level -+ else -+ end -+ end -+ end -+ port_number := opts.option_integer_value ("port", port_number) -+ -+ if opts.option_boolean_value ("force_single_threaded", False) then -+ force_single_threaded - end -- if attached {BOOLEAN} opts.option ("verbose") as l_verbose then -- verbose := l_verbose -- elseif attached {READABLE_STRING_GENERAL} opts.option ("verbose") as l_verbose_str then -- verbose := l_verbose_str.as_lower.same_string ("true") -+ max_concurrent_connections := opts.option_integer_value ("max_concurrent_connections", max_concurrent_connections) -+ max_tcp_clients := opts.option_integer_value ("max_tcp_clients", max_tcp_clients) -+ socket_timeout := opts.option_integer_value ("socket_timeout", socket_timeout) -+ socket_recv_timeout := opts.option_integer_value ("socket_recv_timeout", socket_recv_timeout) -+ keep_alive_timeout := opts.option_integer_value ("keep_alive_timeout", keep_alive_timeout) -+ max_keep_alive_requests := opts.option_integer_value ("max_keep_alive_requests", max_keep_alive_requests) -+ -+ if -+ opts.option_boolean_value ("ssl_enabled", ssl_enabled) and then -+ attached opts.option_string_32_value ("ssl_protocol", "tls_1_2") as ssl_prot -+ then -+ ssl_settings := [ssl_prot, opts.option_string_32_value ("ssl_ca_crt", Void), opts.option_string_32_value ("ssl_ca_key", Void)] - end - end - -@@ -76,18 +131,27 @@ feature {NONE} -- Initialization - update_configuration (conn.configuration) - end - -+ force_single_threaded -+ -- Set `single_threaded' to True. -+ do -+ max_concurrent_connections := 1 -+ end -+ - feature -- Execution - - update_configuration (cfg: like connector.configuration) - do -- if single_threaded then -- cfg.set_force_single_threaded (True) -- end - cfg.set_is_verbose (verbose) -- if attached server_name as l_server_name then -- cfg.set_http_server_name (l_server_name) -- end -+ cfg.set_verbose_level (verbose_level) -+ cfg.set_ssl_settings (ssl_settings) -+ cfg.set_http_server_name (server_name) - cfg.http_server_port := port_number -+ cfg.set_max_concurrent_connections (max_concurrent_connections) -+ cfg.set_max_tcp_clients (max_tcp_clients) -+ cfg.set_socket_timeout (socket_timeout) -+ cfg.set_socket_recv_timeout (socket_recv_timeout) -+ cfg.set_keep_alive_timeout (keep_alive_timeout) -+ cfg.set_max_keep_alive_requests (max_keep_alive_requests) - end - - launch -@@ -98,14 +162,20 @@ feature -- Execution - do - conn := connector - conn.set_base (base_url) -- debug ("nino") -+ debug ("ew_standalone") - if verbose then - io.error.put_string ("Launching standalone web server on port " + port_number.out) -+ if ssl_enabled then -+ io.error.put_string ("%N https://") -+ else -+ io.error.put_string ("%N http://") -+ end - if attached server_name as l_name then -- io.error.put_string ("%N http://" + l_name + ":" + port_number.out + "/" + base_url + "%N") -+ io.error.put_string (l_name) - else -- io.error.put_string ("%N http://localhost:" + port_number.out + "/" + base_url + "%N") -+ io.error.put_string ("localhost") - end -+ io.error.put_string (":" + port_number.out + "/" + base_url + "%N") - end - end - update_configuration (conn.configuration) -@@ -114,15 +184,15 @@ feature -- Execution - - feature -- Callback - -- on_launched_actions: ACTION_SEQUENCE [TUPLE [WGI_STANDALONE_CONNECTOR [G]]] -+ on_launched_actions: ACTION_SEQUENCE [TUPLE [like connector]] - -- Actions triggered when launched - -- on_stopped_actions: ACTION_SEQUENCE [TUPLE [WGI_STANDALONE_CONNECTOR [G]]] -+ on_stopped_actions: ACTION_SEQUENCE [TUPLE [like connector]] - -- Actions triggered when stopped - - feature {NONE} -- Implementation - -- on_launched (conn: WGI_STANDALONE_CONNECTOR [G]) -+ on_launched (conn: like connector) - do - on_launched_actions.call ([conn]) - end -@@ -134,8 +204,29 @@ feature {NONE} -- Implementation - base_url: READABLE_STRING_8 - - verbose: BOOLEAN -+ verbose_level: INTEGER -+ -- Help defining the verbosity. -+ -- The higher, the more output. -+ -+ ssl_settings: detachable TUPLE [protocol: READABLE_STRING_GENERAL; ca_crt, ca_key: detachable READABLE_STRING_GENERAL] -+ -+ ssl_enabled: BOOLEAN -+ -- Is secure server? i.e using SSL? -+ do -+ Result := attached ssl_settings as ssl and then attached ssl.protocol as prot and then not prot.is_whitespace -+ end -+ -+ max_concurrent_connections: INTEGER -+ max_tcp_clients: INTEGER -+ socket_timeout: INTEGER -+ socket_recv_timeout: INTEGER -+ keep_alive_timeout: INTEGER -+ max_keep_alive_requests: INTEGER - - single_threaded: BOOLEAN -+ do -+ Result := max_concurrent_connections = 0 -+ end - - feature -- Status report - -diff --git a/library/server/wsf/connector/standalone_websocket-safe.ecf b/library/server/wsf/connector/standalone_websocket-safe.ecf -new file mode 100644 -index 0000000..01484e5 ---- /dev/null -+++ b/library/server/wsf/connector/standalone_websocket-safe.ecf -@@ -0,0 +1,25 @@ -+ -+ -+ -+ -+ -+ /EIFGENs$ -+ /\.git$ -+ /\.svn$ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/library/server/wsf/connector/standalone_websocket.ecf b/library/server/wsf/connector/standalone_websocket.ecf -new file mode 100644 -index 0000000..0783e77 ---- /dev/null -+++ b/library/server/wsf/connector/standalone_websocket.ecf -@@ -0,0 +1,25 @@ -+ -+ -+ -+ -+ -+ /EIFGENs$ -+ /\.git$ -+ /\.svn$ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/library/server/wsf/connector/standalone_websocket/websocket/event/web_socket_event_i.e b/library/server/wsf/connector/standalone_websocket/websocket/event/web_socket_event_i.e -new file mode 100644 -index 0000000..9ad0fec ---- /dev/null -+++ b/library/server/wsf/connector/standalone_websocket/websocket/event/web_socket_event_i.e -@@ -0,0 +1,137 @@ -+note -+ description: "[ -+ Websocket callback events for actions like opening and closing the connection, -+ sending and receiving messages, and listening. -+ -+ Define the websocket events: -+ - on_open -+ - on_binary -+ - on_text -+ - on_close -+ -+ note: the following features could also be redefined: -+ - on_pong -+ - on_ping -+ - on_unsupported -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ WEB_SOCKET_EVENT_I -+ -+inherit -+ WEB_SOCKET_CONSTANTS -+ -+ REFACTORING_HELPER -+ -+feature -- Web Socket Interface -+ -+ on_event (ws: WEB_SOCKET; a_message: detachable READABLE_STRING_8; a_opcode: INTEGER) -+ -- Called when a frame from the client has been receive -+ require -+ ws_attached: ws /= Void -+ ws_valid: ws.is_open_read and then ws.is_open_write -+ local -+ l_message: READABLE_STRING_8 -+ do -+ debug ("ws") -+ ws.log ("%Non_event (ws, a_message, " + opcode_name (a_opcode) + ")%N", {HTTPD_LOGGER_CONSTANTS}.debug_level) -+ end -+ if a_message = Void then -+ create {STRING} l_message.make_empty -+ else -+ l_message := a_message -+ end -+ -+ if a_opcode = Binary_frame then -+ on_binary (ws, l_message) -+ elseif a_opcode = Text_frame then -+ on_text (ws, l_message) -+ elseif a_opcode = Pong_frame then -+ on_pong (ws, l_message) -+ elseif a_opcode = Ping_frame then -+ on_ping (ws, l_message) -+ elseif a_opcode = Connection_close_frame then -+ on_connection_close (ws, "") -+ else -+ on_unsupported (ws, l_message, a_opcode) -+ end -+ end -+ -+feature -- Websocket events -+ -+ on_open (ws: WEB_SOCKET) -+ -- Called after handshake, indicates that a complete WebSocket connection has been established. -+ require -+ ws_attached: ws /= Void -+ ws_valid: ws.is_open_read and then ws.is_open_write -+ deferred -+ end -+ -+ on_binary (ws: WEB_SOCKET; a_message: READABLE_STRING_8) -+ require -+ ws_attached: ws /= Void -+ ws_valid: ws.is_open_read and then ws.is_open_write -+ deferred -+ end -+ -+ on_text (ws: WEB_SOCKET; a_message: READABLE_STRING_8) -+ require -+ ws_attached: ws /= Void -+ ws_valid: ws.is_open_read and then ws.is_open_write -+ deferred -+ end -+ -+ on_close (ws: detachable WEB_SOCKET) -+ -- Called after the WebSocket connection is closed. -+ deferred -+ end -+ -+feature -- Websocket events: implemented -+ -+ on_pong (ws: WEB_SOCKET; a_message: READABLE_STRING_8) -+ require -+ ws_attached: ws /= Void -+ ws_valid: ws.is_open_read and then ws.is_open_write -+ do -+ -- log ("Its a pong frame") -+ -- at first we ignore pong -+ -- FIXME: provide better explanation -+ end -+ -+ on_ping (ws: WEB_SOCKET; a_message: READABLE_STRING_8) -+ require -+ ws_attached: ws /= Void -+ ws_valid: ws.is_open_read and then ws.is_open_write -+ do -+ ws.send (Pong_frame, a_message) -+ end -+ -+ on_unsupported (ws: WEB_SOCKET; a_message: READABLE_STRING_8; a_opcode: INTEGER) -+ require -+ ws_attached: ws /= Void -+ ws_valid: ws.is_open_read and then ws.is_open_write -+ do -+ -- do nothing -+ end -+ -+ on_connection_close (ws: WEB_SOCKET; a_message: detachable READABLE_STRING_8) -+ require -+ ws_attached: ws /= Void -+ ws_valid: ws.is_open_read and then ws.is_open_write -+ do -+ ws.send (Connection_close_frame, "") -+ end -+ -+note -+ 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 -+ 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 -diff --git a/library/server/wsf/connector/standalone_websocket/websocket/event/web_socket_message_type.e b/library/server/wsf/connector/standalone_websocket/websocket/event/web_socket_message_type.e -new file mode 100644 -index 0000000..cd48af0 ---- /dev/null -+++ b/library/server/wsf/connector/standalone_websocket/websocket/event/web_socket_message_type.e -@@ -0,0 +1,39 @@ -+note -+ description: "[ -+ A web socket message has an opcode specifying the type of the message payload. The -+ opcode consists of the last four bits in the first byte of the frame header. -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ EIS: "name=Data Frame", "src=http://tools.ietf.org/html/rfc6455#section-5.6", "protocol=uri" -+ EIS: "name=Control Frame", "src=http://tools.ietf.org/html/rfc6455#section-5.5", "protocol=uri" -+ -+class -+ WEB_SOCKET_MESSAGE_TYPE -+ -+feature -- Data Frames -+ -+ Text: INTEGER = 0x1 -+ -- The data type of the message is text. -+ -+ Binary: INTEGER = 0x2 -+ -- The data type of the message is binary. -+ -+feature -- Control Frames -+ -+ Close: INTEGER = 0x8 -+ -- The client or server is sending a closing -+ -- handshake to the server or client. -+ -+ Ping: INTEGER = 0x9 -+ -- The client or server sends a ping to the server or client. -+ -+ Pong: INTEGER = 0xA -+ -- The client or server sends a pong to the server or client. -+ -+feature -- Reserverd -+ -+ -- Opcodes 0x3-0x7 are reserved for further non-control frames yet to be -+ -- defined. -+ -+end -diff --git a/library/server/wsf/connector/standalone_websocket/websocket/protocol/web_socket_constants.e b/library/server/wsf/connector/standalone_websocket/websocket/protocol/web_socket_constants.e -new file mode 100644 -index 0000000..86e771d ---- /dev/null -+++ b/library/server/wsf/connector/standalone_websocket/websocket/protocol/web_socket_constants.e -@@ -0,0 +1,203 @@ -+note -+ description: "Constants for WebSockets" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ WEB_SOCKET_CONSTANTS -+ -+feature -- Constants -+ -+ -+ HTTP_1_1: STRING = "HTTP/1.1 101 WebSocket Protocol Handshake" -+ -+ Upgrade_ws: STRING = "Upgrade: websocket" -+ -+ Connection_ws: STRING = "Connection: Upgrade" -+ -+ Sec_WebSocket_Origin: STRING = "Sec-WebSocket-Origin: " -+ -+ Sec_WebSocket_Protocol: STRING = "Sec-WebSocket-Protocol: " -+ -+ Sec_WebSocket_Location: STRING = "Sec-WebSocket-Location: " -+ -+ Sec_WebSocket_Version: STRING = "Sec-WebSocket-Version: " -+ -+ Sec_WebSocket_Extensions: STRING = "Sec-WebSocket-Extensions: " -+ -+ WebSocket_Origin: STRING = "WebSocket-Origin: " -+ -+ WebSocket_Protocol: STRING = "WebSocket-Protocol: " -+ -+ WebSocket_Location: STRING = "WebSocket-Location: " -+ -+ Origin: STRING = "Origin" -+ -+ Server: STRING = "EWSS" -+ -+ Sec_WebSocket_Key: STRING = "Sec-WebSocket-Key" -+ -+ Ws_scheme: STRING = "ws://" -+ -+ Wss_scheme: STRING = "wss://" -+ -+ Magic_guid: STRING = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" -+ -+ -- The handshake from the client looks as follows: -+ -+ -- GET /chat HTTP/1.1 -+ -- Host: server.example.com -+ -- Upgrade: websocket -+ -- Connection: Upgrade -+ -- Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== -+ -- Origin: http://example.com -+ -- Sec-WebSocket-Protocol: chat, superchat -+ -- Sec-WebSocket-Version: 13 -+ -+ -- The handshake from the server looks as follows: -+ -+ -- HTTP/1.1 101 Switching Protocols -+ -- Upgrade: websocket -+ -- Connection: Upgrade -+ -- Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= -+ -- Sec-WebSocket-Protocol: chat -+ -+feature -- Opcodes Standard actions -+ -+ --| Maybe we need an enum STANDARD_ACTIONS_OPCODES? -+ -- |Opcode | Meaning | Reference | -+ -- -+--------+-------------------------------------+-----------| -+ -- | 0 | Continuation Frame | RFC 6455 | -+ -- -+--------+-------------------------------------+-----------| -+ -- | 1 | Text Frame | RFC 6455 | -+ -- -+--------+-------------------------------------+-----------| -+ -- | 2 | Binary Frame | RFC 6455 | -+ -- -+--------+-------------------------------------+-----------| -+ -- | 8 | Connection Close Frame | RFC 6455 | -+ -- -+--------+-------------------------------------+-----------| -+ -- | 9 | Ping Frame | RFC 6455 | -+ -- -+--------+-------------------------------------+-----------| -+ -- | 10 | Pong Frame | RFC 6455 | -+ -- -+--------+-------------------------------------+-----------| -+ -+ Continuation_frame: INTEGER = 0 -+ -+ Text_frame: INTEGER = 1 -+ -+ Binary_frame: INTEGER = 2 -+ -+ Connection_close_frame: INTEGER = 8 -+ -+ Ping_frame: INTEGER = 9 -+ -+ Pong_frame: INTEGER = 10 -+ -+ is_control_frame (a_opcode: INTEGER): BOOLEAN -+ -- Is `a_opcode' a control frame? -+ do -+ inspect a_opcode -+ when Connection_close_frame, Ping_frame, Pong_frame then -+ Result := True -+ else -+ end -+ end -+ -+ opcode_name (a_opcode: INTEGER): STRING -+ do -+ inspect a_opcode -+ when Continuation_frame then Result := "Continuation" -+ when Text_frame then Result := "Text" -+ when Binary_frame then Result := "Binary" -+ when Connection_close_frame then Result := "Connection Close" -+ when Ping_frame then Result := "Ping" -+ when Pong_frame then Result := "Pong" -+ else -+ Result := "Unknown-Opcode" -+ end -+ Result := "0x" + a_opcode.to_hex_string + " " + Result -+ end -+ -+feature -- Close code numbers -+ -+ -- Maybe an ENUM CLOSE_CODES -+ -+ -- |Status Code | Meaning | Contact | Reference | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1000 | Normal Closure | hybi@ietf.org | RFC 6455 | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1001 | Going Away | hybi@ietf.org | RFC 6455 | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1002 | Protocol error | hybi@ietf.org | RFC 6455 | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1003 | Unsupported Data| hybi@ietf.org | RFC 6455 | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1004 | ---Reserved---- | hybi@ietf.org | RFC 6455 | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1005 | No Status Rcvd | hybi@ietf.org | RFC 6455 | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1006 | Abnormal Closure| hybi@ietf.org | RFC 6455 | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1007 | Invalid frame | hybi@ietf.org | RFC 6455 | -+ -- | | payload data | | | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1008 | Policy Violation| hybi@ietf.org | RFC 6455 | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1009 | Message Too Big | hybi@ietf.org | RFC 6455 | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1010 | Mandatory Ext. | hybi@ietf.org | RFC 6455 | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1011 | Internal Server | hybi@ietf.org | RFC 6455 | -+ -- | | Error | | | -+ -- -+------------+-----------------+---------------+-----------| -+ -- | 1015 | TLS handshake | hybi@ietf.org | RFC 6455 | -+ -- -+------------+-----------------+---------------+-----------| -+ -+ Normal_closure: INTEGER = 1000 -+ -- Indicates a normal closure, meaning that the purpose for -+ -- which the connection was established has been fulfilled. -+ -+ Going_away: INTEGER = 1001 -+ -- Indicates that an endpoint is "going away", such as a server -+ -- going down or a browser having navigated away from a page. -+ -+ Protocol_error: INTEGER = 1002 -+ -- Indicates that an endpoint is terminating the connection due -+ -- to a protocol error. -+ -+ Unsupported_data: INTEGER = 1003 -+ -- Indicates that an endpoint is terminating the connection -+ -- because it has received a type of data it cannot accept (e.g., an -+ -- endpoint that understands only text data MAY send this if it -+ -- receives a binary message). -+ -+ Invalid_data: INTEGER = 1007 -+ -- Indicates that an endpoint is terminating the connection -+ -- because it has received data within a message that was not -+ -- consistent with the type of the message (e.g., non-UTF-8 [RFC3629] -+ -- data within a text message). -+ -+ Policy_violation: INTEGER = 1008 -+ -- Indicates that an endpoint is terminating the connection -+ -- because it has received a message that violates its policy. This -+ -- is a generic status code that can be returned when there is no -+ -- other more suitable status code (e.g., 1003 or 1009) or if there -+ -- is a need to hide specific details about the policy. -+ -+ Message_too_large: INTEGER = 1009 -+ -- Indicates that an endpoint is terminating the connection -+ -- because it has received a message that is too big for it to -+ -- process. -+ -+ Extension_required: INTEGER = 1010 -+ -- Indicates that an endpoint (client) is terminating the -+ -- connection because it has expected the server to negotiate one or -+ -- more extension, but the server didn't return them in the response -+ -- message of the WebSocket handshake. -+ -+ Internal_error: INTEGER = 1011 -+ -- Indicates that a server is terminating the connection because -+ -- it encountered an unexpected condition that prevented it from -+ -- fulfilling the request. -+ -+ -+end -diff --git a/library/server/wsf/connector/standalone_websocket/websocket/protocol/web_socket_error_frame.e b/library/server/wsf/connector/standalone_websocket/websocket/protocol/web_socket_error_frame.e -new file mode 100644 -index 0000000..af9aa83 ---- /dev/null -+++ b/library/server/wsf/connector/standalone_websocket/websocket/protocol/web_socket_error_frame.e -@@ -0,0 +1,35 @@ -+note -+ description: "Summary description for {WEB_SOCKET_ERROR_FRAME}." -+ author: "" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ WEB_SOCKET_ERROR_FRAME -+ -+create -+ make -+ -+feature {NONE} -- Initialization -+ -+ make (a_code: INTEGER; a_desc: like description) -+ do -+ code := a_code -+ description := a_desc -+ end -+ -+feature -- Access -+ -+ code: INTEGER -+ -+ description: READABLE_STRING_8 -+ -+feature -- Conversion -+ -+ string: STRING -+ do -+ create Result.make_from_string ("Error(" + code.out + "): " + description) -+ end -+ -+ -+end -diff --git a/library/server/wsf/connector/standalone_websocket/websocket/protocol/web_socket_frame.e b/library/server/wsf/connector/standalone_websocket/websocket/protocol/web_socket_frame.e -new file mode 100644 -index 0000000..3f3350a ---- /dev/null -+++ b/library/server/wsf/connector/standalone_websocket/websocket/protocol/web_socket_frame.e -@@ -0,0 +1,437 @@ -+note -+ description: "[ -+ Summary description for {WEB_SOCKET_FRAME}. -+ See Base Framing Protocol: http://tools.ietf.org/html/rfc6455#section-5.2 -+ 0 1 2 3 -+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+ +-+-+-+-+-------+-+-------------+-------------------------------+ -+ |F|R|R|R| opcode|M| Payload len | Extended payload length | -+ |I|S|S|S| (4) |A| (7) | (16/64) | -+ |N|V|V|V| |S| | (if payload len==126/127) | -+ | |1|2|3| |K| | | -+ +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + -+ | Extended payload length continued, if payload len == 127 | -+ + - - - - - - - - - - - - - - - +-------------------------------+ -+ | |Masking-key, if MASK set to 1 | -+ +-------------------------------+-------------------------------+ -+ | Masking-key (continued) | Payload Data | -+ +-------------------------------- - - - - - - - - - - - - - - - + -+ : Payload Data continued ... : -+ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + -+ | Payload Data continued ... | -+ +---------------------------------------------------------------+ -+ -+ Check the `check_utf_8_validity_on_chop' if there is performance issue -+ with bigger data. -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ EIS: "name=Websocket RFC6455 section-5.2", "protocol=URI", "src=http://tools.ietf.org/html/rfc6455#section-5.2", "tag=rfc" -+ -+class -+ WEB_SOCKET_FRAME -+ -+inherit -+ ANY -+ -+ WEB_SOCKET_CONSTANTS -+ -+create -+ make, -+ make_as_injected_control -+ -+feature {NONE} -- Initialization -+ -+ make (a_opcode: INTEGER; flag_is_fin: BOOLEAN) -+ -- Create current frame with opcode `a_opcode' -+ -- and `a_fin' to indicate if this is the final fragment. -+ do -+ is_incomplete := False -+ opcode := a_opcode -+ is_fin := flag_is_fin -+ -+ inspect opcode -+ when -+ Continuation_frame, -- 0 -+ Text_frame, -- 1 -+ Binary_frame -- 2 -+ then -+ --| Supported opcode -+ when -+ Connection_close_frame, -- 8 -+ Ping_frame, -- 9 -+ Pong_frame -- 10 -+ then -+ --| Supported control opcode -+ -- All control frames MUST have a payload length of 125 bytes or less -+ -- and MUST NOT be fragmented. -+ if flag_is_fin then -+ -- So far it is valid. -+ else -+ report_error (Protocol_error, "Control frames MUST NOT be fragmented.") -+ end -+ else -+ report_error (Protocol_error, "Unknown opcode") -+ end -+ end -+ -+ make_as_injected_control (a_opcode: INTEGER; a_parent: WEB_SOCKET_FRAME) -+ require -+ parent_is_not_control_frame: not a_parent.is_control -+ a_opcode_is_control_frame: is_control_frame (a_opcode) -+ do -+ make (a_opcode, True) -+ parent := a_parent -+ a_parent.add_injected_control_frame (Current) -+ end -+ -+feature -- Access -+ -+ opcode: INTEGER -+ -- CONTINUOUS, TEXT, BINARY, PING, PONG, CLOSING -+ -+ is_fin: BOOLEAN -+ -- is the final fragment in a message? -+ -+ fragment_count: INTEGER -+ -+ payload_length: NATURAL_64 -+ payload_data: detachable STRING_8 -+ -- Maybe we need a buffer here. -+ -+ uncoded_payload_data: detachable STRING_32 -+ local -+ utf: UTF_CONVERTER -+ do -+ if attached payload_data as d then -+ Result := utf.utf_8_string_8_to_string_32 (d) -+ end -+ end -+ -+ error: detachable WEB_SOCKET_ERROR_FRAME -+ -- Describe the type of error -+ -+feature -- Access: injected control frames -+ -+ injected_control_frames: detachable LIST [WEB_SOCKET_FRAME] -+ -+ parent: detachable WEB_SOCKET_FRAME -+ -- If Current is injected, `parent' is the related fragmented frame -+ -+ is_injected_control: BOOLEAN -+ do -+ Result := parent /= Void -+ ensure -+ Result implies (is_control_frame (opcode)) -+ end -+ -+feature -- Operation -+ -+ update_fin (a_flag_is_fin: BOOLEAN) -+ do -+ is_fin := a_flag_is_fin -+ end -+ -+feature {WEB_SOCKET_FRAME} -- Change: injected control frames -+ -+ add_injected_control_frame (f: WEB_SOCKET_FRAME) -+ require -+ Current_is_not_control: not is_control -+ f_is_control_frame: f.is_control -+ parented_to_current: f.parent = Current -+ local -+ lst: like injected_control_frames -+ do -+ lst := injected_control_frames -+ if lst = Void then -+ create {ARRAYED_LIST [WEB_SOCKET_FRAME]} lst.make (1) -+ injected_control_frames := lst -+ end -+ lst.force (f) -+ ensure -+ parented_to_current: f.parent = Current -+ end -+ -+ remove_injected_control_frame (f: WEB_SOCKET_FRAME) -+ require -+ Current_is_not_control: not is_control -+ f_is_control_frame: f.is_control -+ parented_to_current: f.parent = Current -+ local -+ lst: like injected_control_frames -+ do -+ lst := injected_control_frames -+ if lst /= Void then -+ lst.prune (f) -+ if lst.is_empty then -+ injected_control_frames := Void -+ end -+ end -+ end -+ -+feature -- Query -+ -+ is_binary: BOOLEAN -+ do -+ Result := opcode = binary_frame -+ end -+ -+ is_text: BOOLEAN -+ do -+ Result := opcode = text_frame -+ end -+ -+ is_continuation: BOOLEAN -+ do -+ Result := opcode = continuation_frame -+ end -+ -+ is_connection_close: BOOLEAN -+ do -+ Result := opcode = connection_close_frame -+ end -+ -+ is_control: BOOLEAN -+ do -+ inspect opcode -+ when connection_close_frame, Ping_frame, Pong_frame then -+ Result := True -+ else -+ end -+ end -+ -+ is_ping: BOOLEAN -+ do -+ Result := opcode = ping_frame -+ end -+ -+ is_pong: BOOLEAN -+ do -+ Result := opcode = pong_frame -+ end -+ -+feature -- Status report -+ -+ is_valid: BOOLEAN -+ do -+ Result := not has_error -+ end -+ -+ is_incomplete: BOOLEAN -+ -+ has_error: BOOLEAN -+ do -+ Result := error /= Void -+ end -+ -+feature -- Change -+ -+ increment_fragment_count -+ do -+ fragment_count := fragment_count + 1 -+ end -+ -+ check_utf_8_validity_on_chop: BOOLEAN = False -+ -- True: check for each chop -+ -- False: check only for each fragment -+ --| see autobahntestsuite #6.4.3 and #6.4.4 -+ -+ append_payload_data_chop (a_data: STRING_8; a_len: INTEGER; a_flag_chop_complete: BOOLEAN) -+ do -+ if a_flag_chop_complete then -+ increment_fragment_count -+ end -+ if attached payload_data as l_payload_data then -+ l_payload_data.append (a_data) -+ else -+ payload_data := a_data -+ end -+ payload_length := payload_length + a_len.to_natural_64 -+ -+ if is_text then -+ if is_fin and a_flag_chop_complete then -+ -- Check the whole message is a valid UTF-8 string -+ if attached payload_data as d then -+ if not is_valid_utf_8_string (d) then -+ report_error (invalid_data, "The text message is not a valid UTF-8 text!") -+ end -+ else -+ -- empty payload?? -+ end -+ elseif check_utf_8_validity_on_chop or else a_flag_chop_complete then -+ -- Check the payload data as utf-8 stream (may be incomplete at this point) -+ if not is_valid_text_payload_stream then -+ report_error (invalid_data, "This is not a valid UTF-8 stream!") -+ -- is_valid implies the connection will be closed! -+ end -+ end -+ end -+ end -+ -+ report_error (a_code: INTEGER; a_description: READABLE_STRING_8) -+ require -+ not has_error -+ do -+ create error.make (a_code, a_description) -+ ensure -+ has_error: has_error -+ is_not_valid: not is_valid -+ end -+ -+feature {NONE} -- Helper -+ -+ last_utf_8_stream_validation_position: INTEGER -+ -- In relation with `is_valid_utf_8 (.., a_is_stream=True)' -+ -+ is_valid_text_payload_stream: BOOLEAN -+ require -+ is_text_frame: is_text -+ do -+ if attached payload_data as s then -+ Result := is_valid_utf_8 (s, not is_fin) -+ end -+ end -+ -+ is_valid_utf_8_string (s: READABLE_STRING_8): BOOLEAN -+ do -+ Result := is_valid_utf_8 (s, False) -+-- and (create {UTF_CONVERTER}).is_valid_utf_8_string_8 (s) -+ end -+ -+ is_valid_utf_8 (s: READABLE_STRING_8; a_is_stream: BOOLEAN): BOOLEAN -+ -- UTF-8 validity checker. -+ note -+ EIS: "name=UTF-8 RFC3629", "protocol=URI", "src=https://tools.ietf.org/html/rfc3629", "tag=rfc" -+ require -+ is_text_frame: is_text -+ local -+ i: like {STRING_8}.count -+ n: like {STRING_8}.count -+ c,c2,c3,c4,w: NATURAL_32 -+ l_is_incomplete_stream: BOOLEAN -+ do -+ Result := True -+ -- Following code also check that codepoint is between 0 and 0x10FFFF -+ -- (as expected by spec, and tested by autobahn ws testsuite) -+ from -+ if a_is_stream then -+ i := last_utf_8_stream_validation_position -- to avoid recomputing from the beginning each time. -+ else -+ i := 0 -+ end -+ n := s.count -+ until -+ i >= n or not Result -+ loop -+ i := i + 1 -+ c := s.code (i) -+ if c <= 0x7F then -+ -- 0xxxxxxx -+ w := c -+ elseif c <= 0xC1 then -+ -- The octet values C0, C1, F5 to FF never appear. -+ --| case 0xC0 and 0xC1 -+ Result := False -+ elseif (c & 0xE0) = 0xC0 then -+ -- 110xxxxx 10xxxxxx -+ i := i + 1 -+ if i <= n then -+ c2 := s.code (i) -+ if -+ (c2 & 0xC0) = 0x80 -+ then -+ w := ((c & 0x1F) |<< 6) -+ | (c2 & 0x3F) -+ Result := 0x80 <= w and w <= 0x7FF -+ else -+ Result := False -+ end -+ else -+ l_is_incomplete_stream := True -+ end -+ elseif (c & 0xF0) = 0xE0 then -+ -- 1110xxxx 10xxxxxx 10xxxxxx -+ i := i + 2 -+ if i <= n then -+ c2 := s.code (i - 1) -+ c3 := s.code (i) -+ if -+ (c2 & 0xC0) = 0x80 and -+ (c3 & 0xC0) = 0x80 -+ then -+ w := ((c & 0xF) |<< 12) -+ | ((c2 & 0x3F) |<< 6) -+ | (c3 & 0x3F) -+ if 0x800 <= w and w <= 0xFFFF then -+ if 0xD800 <= w and w <= 0xDFFF then -+ -- The definition of UTF-8 prohibits encoding character numbers between U+D800 and U+DFFF -+ Result := False -+ end -+ else -+ Result := False -+ end -+ else -+ Result := False -+ end -+ else -+ if i - 1 <= n then -+ Result := (s.code (i - 1) & 0xC0) = 0x80 -+ end -+ l_is_incomplete_stream := True -+ end -+ elseif (c & 0xF8) = 0xF0 then -- 0001 0000-0010 FFFF -+ -- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx -+ if 0xF5 <= c and c <= 0xFF then -+ -- The octet values C0, C1, F5 to FF never appear. -+ Result := False -+ else -+ i := i + 3 -+ if i <= n then -+ c2 := s.code (i - 2) -+ c3 := s.code (i - 1) -+ c4 := s.code (i) -+ if -+ (c2 & 0xC0) = 0x80 and -+ (c3 & 0xC0) = 0x80 and -+ (c4 & 0xC0) = 0x80 -+ then -+ w := ((c & 0x7) |<< 18) | -+ ((c2 & 0x3F) |<< 12) | -+ ((c3 & 0x3F) |<< 6) | -+ (c4 & 0x3F) -+ Result := 0x1_0000 <= w and w <= 0x10_FFFF -+ else -+ Result := False -+ end -+ else -+ if i - 2 <= n then -+ c2 := s.code (i - 2) -+ Result := (c2 & 0xC0) = 0x80 -+ if Result then -+ if c = 0xF4 and c2 >= 0x90 then -+ --| any byte 10xxxxxx (i.e >= 0x80) that would come after, -+ -- will result in out of range code point -+ -- indeed 0xF4 0x90 0x80 0x80 = 0x1100 0000 > 0x10_FFFF -+ Result := False -+ elseif i - 1 <= n then -+ Result := (s.code (i - 1) & 0xC0) = 0x80 -+ end -+ end -+ end -+ l_is_incomplete_stream := True -+ end -+ end -+ else -+ -- Invalid byte in UTF-8 -+ Result := False -+ end -+ if Result then -+ if l_is_incomplete_stream then -+ Result := a_is_stream -+ elseif a_is_stream then -+ last_utf_8_stream_validation_position := i -+ end -+ end -+ end -+ end -+end -diff --git a/library/server/wsf/connector/standalone_websocket/websocket/web_socket.e b/library/server/wsf/connector/standalone_websocket/websocket/web_socket.e -new file mode 100644 -index 0000000..e301f25 ---- /dev/null -+++ b/library/server/wsf/connector/standalone_websocket/websocket/web_socket.e -@@ -0,0 +1,805 @@ -+note -+ description: "[ -+ Object representing the websocket connection. -+ It contains the `request` and `response`, and more important the `socket` itself. -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ WEB_SOCKET -+ -+inherit -+ WGI_STANDALONE_CONNECTOR_EXPORTER -+ -+ WSF_RESPONSE_EXPORTER -+ -+ WGI_EXPORTER -+ -+ HTTPD_LOGGER_CONSTANTS -+ -+ WEB_SOCKET_CONSTANTS -+ -+ SHARED_BASE64 -+ -+create -+ make -+ -+feature {NONE} -- Initialization -+ -+ make (req: WSF_REQUEST; res: WSF_RESPONSE) -+ do -+ request := req -+ response := res -+ is_verbose := False -+ verbose_level := notice_level -+ -+ if -+ attached {WGI_STANDALONE_INPUT_STREAM} req.input as r_input -+ then -+ socket := r_input.source -+ else -+ create socket.make_empty -+ check has_socket: False end -+ end -+ end -+ -+feature -- Access -+ -+ socket: HTTPD_STREAM_SOCKET -+ -- Underlying connected socket. -+ -+feature {NONE} -- Access -+ -+ request: WSF_REQUEST -+ -- Associated request. -+ -+ response: WSF_RESPONSE -+ -- Associated response stream. -+ -+feature -- Access -+ -+ is_websocket: BOOLEAN -+ -- Does `open_ws_handshake' detect valid websocket upgrade handshake? -+ -+feature -- Settings -+ -+ is_verbose: BOOLEAN -+ -- Output verbose log messages? -+ -+ verbose_level: INTEGER -+ -- Level of verbosity. -+ -+feature -- Status -+ -+ has_error: BOOLEAN -+ -- Error occured during processing? -+ -+feature -- Socket status -+ -+ is_ready_for_reading: BOOLEAN -+ -- Is `socket' ready for reading? -+ --| at this point, socket should be set to blocking. -+ do -+ Result := socket.ready_for_reading -+ end -+ -+ is_open_read: BOOLEAN -+ -- Is `socket' open for reading? -+ do -+ Result := socket.is_open_read -+ end -+ -+ is_open_write: BOOLEAN -+ -- Is `socket' open for writing? -+ do -+ Result := socket.is_open_write -+ end -+ -+ socket_descriptor: INTEGER -+ -- Descriptor for current `socket'. -+ do -+ Result := socket.descriptor -+ end -+ -+feature -- Element change -+ -+ set_is_verbose (b: BOOLEAN) -+ do -+ is_verbose := b -+ end -+ -+ set_verbose_level (lev: INTEGER) -+ do -+ verbose_level := lev -+ end -+ -+feature -- Basic operation -+ -+ put_error (a_message: READABLE_STRING_8) -+ do -+ response.put_error (a_message) -+ end -+ -+ log (m: READABLE_STRING_8; lev: INTEGER) -+ -- Log `m' in the error channel, i.e stderr for standalone. -+ do -+ if is_verbose then -+ put_error (m) -+ end -+ end -+ -+feature -- Basic Operation -+ -+ open_ws_handshake -+ -- The opening handshake is intended to be compatible with HTTP-based -+ -- server-side software and intermediaries, so that a single port can be -+ -- used by both HTTP clients alking to that server and WebSocket -+ -- clients talking to that server. To this end, the WebSocket client's -+ -- handshake is an HTTP Upgrade request: -+ -+ -- GET /chat HTTP/1.1 -+ -- Host: server.example.com -+ -- Upgrade: websocket -+ -- Connection: Upgrade -+ -- Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== -+ -- Origin: http://example.com -+ -- Sec-WebSocket-Protocol: chat, superchat -+ -- Sec-WebSocket-Version: 13 -+ local -+ l_sha1: SHA1 -+ l_key : STRING -+ req: like request -+ res: like response -+ do -+ -- Reset values. -+ is_websocket := False -+ has_error := False -+ -+ -- Local cache. -+ req := request -+ res := response -+ -+ -- Reading client's opening GT -+ -+ -- TODO extract to a validator handshake or something like that. -+ if is_verbose then -+ log ("%NReceive <====================", debug_level) -+ if attached req.raw_header_data as rhd then -+ log (rhd, debug_level) -+ end -+ end -+ if -+ req.is_get_request_method and then -- MUST be GET request! -+ attached req.meta_string_variable ("HTTP_UPGRADE") as l_upgrade_key and then -+ l_upgrade_key.is_case_insensitive_equal_general ("websocket") -- Upgrade header must be present with value websocket -+ then -+ is_websocket := True -+ socket.set_blocking -+ if -+ attached req.meta_string_variable ("HTTP_SEC_WEBSOCKET_KEY") as l_ws_key and then -- Sec-websocket-key must be present -+ attached req.meta_string_variable ("HTTP_CONNECTION") as l_connection_key and then -- Connection header must be present with value Upgrade -+ l_connection_key.has_substring ("Upgrade") and then -+ attached req.meta_string_variable ("HTTP_SEC_WEBSOCKET_VERSION") as l_version_key and then -- Version header must be present with value 13 -+ l_version_key.is_case_insensitive_equal ("13") and then -+ attached req.http_host -- Host header must be present -+ then -+ if is_verbose then -+ log ("key " + l_ws_key, debug_level) -+ end -+ -- Sending the server's opening handshake -+ create l_sha1.make -+ l_sha1.update_from_string (l_ws_key + magic_guid) -+ l_key := Base64_encoder.encoded_string (digest (l_sha1)) -+ res.header.add_header_key_value ("Upgrade", "websocket") -+ res.header.add_header_key_value ("Connection", "Upgrade") -+ res.header.add_header_key_value ("Sec-WebSocket-Accept", l_key) -+ -+ if is_verbose then -+ log ("%N================> Send Handshake", debug_level) -+ if attached {HTTP_HEADER} res.header as h then -+ log (h.string, debug_level) -+ end -+ end -+ res.set_status_code_with_reason_phrase (101, "Switching Protocols") -+ res.wgi_response.push -+ else -+ has_error := True -+ if is_verbose then -+ log ("Error (opening_handshake)!!!", debug_level) -+ end -+ -- If we cannot complete the handshake, then the server MUST stop processing the client's handshake and return an HTTP response with an -+ -- appropriate error code (such as 400 Bad Request). -+ res.set_status_code_with_reason_phrase (400, "Bad Request") -+ end -+ else -+ is_websocket := False -+ end -+ end -+ -+feature -- Response! -+ -+ send (a_opcode:INTEGER; a_message: READABLE_STRING_8) -+ local -+ i: INTEGER -+ l_chunk_size: INTEGER -+ l_chunk: READABLE_STRING_8 -+ l_header_message: STRING -+ l_message_count: INTEGER -+ n: NATURAL_64 -+ retried: BOOLEAN -+ do -+ debug ("ws") -+ print (">>do_send (..., "+ opcode_name (a_opcode) +", ..)%N") -+ end -+ if not retried then -+ create l_header_message.make_empty -+ l_header_message.append_code ((0x80 | a_opcode).to_natural_32) -+ l_message_count := a_message.count -+ n := l_message_count.to_natural_64 -+ if l_message_count > 0xffff then -+ --! Improve. this code needs to be checked. -+ l_header_message.append_code ((0 | 127).to_natural_32) -+ l_header_message.append_character ((n |>> 56).to_character_8) -+ l_header_message.append_character ((n |>> 48).to_character_8) -+ l_header_message.append_character ((n |>> 40).to_character_8) -+ l_header_message.append_character ((n |>> 32).to_character_8) -+ l_header_message.append_character ((n |>> 24).to_character_8) -+ l_header_message.append_character ((n |>> 16).to_character_8) -+ l_header_message.append_character ((n |>> 8).to_character_8) -+ l_header_message.append_character ( n.to_character_8) -+ elseif l_message_count > 125 then -+ l_header_message.append_code ((0 | 126).to_natural_32) -+ l_header_message.append_code ((n |>> 8).as_natural_32) -+ l_header_message.append_character (n.to_character_8) -+ else -+ l_header_message.append_code (n.as_natural_32) -+ end -+ socket.put_string (l_header_message) -+ -+ l_chunk_size := 16_384 -- 16K TODO: see if we should make it customizable. -+ if l_message_count < l_chunk_size then -+ socket.put_string (a_message) -+ else -+ from -+ i := 0 -+ until -+ l_chunk_size = 0 -+ loop -+ debug ("ws") -+ print ("Sending chunk " + (i + 1).out + " -> " + (i + l_chunk_size).out +" / " + l_message_count.out + "%N") -+ end -+ l_chunk := a_message.substring (i + 1, l_message_count.min (i + l_chunk_size)) -+ socket.put_string (l_chunk) -+ if l_chunk.count < l_chunk_size then -+ l_chunk_size := 0 -+ end -+ i := i + l_chunk_size -+ end -+ debug ("ws") -+ print ("Sending chunk done%N") -+ end -+ end -+ else -+ -- FIXME: what should be done on rescue? -+ end -+ rescue -+ retried := True -+ io.put_string ("Internal error in " + generator + ".do_send (conn, a_opcode=" + a_opcode.out + ", a_message) !%N") -+ retry -+ end -+ -+ next_frame: detachable WEB_SOCKET_FRAME -+ -- TODO Binary messages -+ -- Handle error responses in a better way. -+ -- IDEA: -+ -- class FRAME -+ -- is_fin: BOOLEAN -+ -- opcode: WEB_SOCKET_STATUS_CODE (TEXT, BINARY, CLOSE, CONTINUE,PING, PONG) -+ -- data/payload -+ -- status_code: #see Status Codes http://tools.ietf.org/html/rfc6455#section-7.3 -+ -- has_error -+ -- -+ -- See Base Framing Protocol: http://tools.ietf.org/html/rfc6455#section-5.2 -+ -- 0 1 2 3 -+ -- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+ -- +-+-+-+-+-------+-+-------------+-------------------------------+ -+ -- |F|R|R|R| opcode|M| Payload len | Extended payload length | -+ -- |I|S|S|S| (4) |A| (7) | (16/64) | -+ -- |N|V|V|V| |S| | (if payload len==126/127) | -+ -- | |1|2|3| |K| | | -+ -- +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + -+ -- | Extended payload length continued, if payload len == 127 | -+ -- + - - - - - - - - - - - - - - - +-------------------------------+ -+ -- | |Masking-key, if MASK set to 1 | -+ -- +-------------------------------+-------------------------------+ -+ -- | Masking-key (continued) | Payload Data | -+ -- +-------------------------------- - - - - - - - - - - - - - - - + -+ -- : Payload Data continued ... : -+ -- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + -+ -- | Payload Data continued ... | -+ -- +---------------------------------------------------------------+ -+ note -+ EIS: "name=WebSocket RFC", "protocol=URI", "src=http://tools.ietf.org/html/rfc6455#section-5.2" -+ require -+ socket_in_blocking_mode: socket.is_blocking -+ local -+ l_socket: like socket -+ l_opcode: INTEGER -+ l_len: INTEGER -+ l_remaining_len: INTEGER -+ l_payload_len: NATURAL_64 -+ l_masking_key: detachable READABLE_STRING_8 -+ l_chunk: STRING -+ l_rsv: BOOLEAN -+ l_fin: BOOLEAN -+ l_has_mask: BOOLEAN -+ l_chunk_size: INTEGER -+ l_byte: INTEGER -+ l_fetch_count: INTEGER -+ l_bytes_read: INTEGER -+ s: STRING -+ is_data_frame_ok: BOOLEAN -- Is the last process data framing ok? -+ retried: BOOLEAN -+ do -+ if not retried then -+ l_socket := socket -+ debug ("ws") -+ print ("next_frame:%N") -+ end -+ from -+ is_data_frame_ok := True -+ until -+ l_fin or not is_data_frame_ok -+ loop -+ -- multi-frames or continue is only valid for Binary or Text -+ s := next_bytes (l_socket, 1) -+ if s.is_empty then -+ is_data_frame_ok := False -+ debug ("ws") -+ print ("[ERROR] incomplete_data!%N") -+ end -+ else -+ l_byte := s [1].code -+ debug ("ws") -+ print (" fin,rsv(3),opcode(4)=") -+ print (to_byte_representation (l_byte)) -+ print ("%N") -+ end -+ l_fin := l_byte & (0b10000000) /= 0 -+ l_rsv := l_byte & (0b01110000) = 0 -+ l_opcode := l_byte & 0b00001111 -+ if Result /= Void then -+ if l_opcode = Result.opcode then -+ -- should not occur in multi-fragment frame! -+ create Result.make (l_opcode, l_fin) -+ Result.report_error (protocol_error, "Unexpected injected frame") -+ elseif l_opcode = continuation_frame then -+ -- Expected -+ Result.update_fin (l_fin) -+ elseif is_control_frame (l_opcode) then -+ -- Control frames (see Section 5.5) MAY be injected in the middle of -+ -- a fragmented message. Control frames themselves MUST NOT be fragmented. -+ -- if the l_opcode is a control frame then there is an error!!! -+ -- CLOSE, PING, PONG -+ create Result.make_as_injected_control (l_opcode, Result) -+ else -+ -- should not occur in multi-fragment frame! -+ create Result.make (l_opcode, l_fin) -+ Result.report_error (protocol_error, "Unexpected frame") -+ end -+ else -+ create Result.make (l_opcode, l_fin) -+ if Result.is_continuation then -+ -- Continuation frame is not expected without parent frame! -+ Result.report_error (protocol_error, "There is no message to continue!") -+ end -+ end -+ if Result.is_valid then -+ --| valid frame/fragment -+ if is_verbose then -+ log ("+ frame " + opcode_name (l_opcode) + " (fin=" + l_fin.out + ")", debug_level) -+ end -+ -+ -- rsv validation -+ if not l_rsv then -+ -- RSV1, RSV2, RSV3: 1 bit each -+ -+ -- MUST be 0 unless an extension is negotiated that defines meanings -+ -- for non-zero values. If a nonzero value is received and none of -+ -- the negotiated extensions defines the meaning of such a nonzero -+ -- value, the receiving endpoint MUST _Fail the WebSocket -+ -- Connection_ -+ -+ -- FIXME: add support for extension ? -+ Result.report_error (protocol_error, "RSV values MUST be 0 unless an extension is negotiated that defines meanings for non-zero values") -+ end -+ else -+ if is_verbose then -+ log ("+ INVALID frame " + opcode_name (l_opcode) + " (fin=" + l_fin.out + ")", debug_level) -+ end -+ end -+ -+ -- At the moment only TEXT, (pending Binary) -+ if Result.is_valid then -+ if Result.is_text or Result.is_binary or Result.is_control then -+ -- Reading next byte (mask+payload_len) -+ s := next_bytes (l_socket, 1) -+ if s.is_empty then -+ Result.report_error (invalid_data, "Incomplete data for mask and payload len") -+ else -+ l_byte := s [1].code -+ debug ("ws") -+ print (" mask,payload_len(7)=") -+ print (to_byte_representation (l_byte)) -+ io.put_new_line -+ end -+ l_has_mask := l_byte & (0b10000000) /= 0 -- MASK -+ l_len := l_byte & 0b01111111 -- 7bits -+ -+ debug ("ws") -+ print (" payload_len=" + l_len.out) -+ io.put_new_line -+ end -+ if Result.is_control and then l_len > 125 then -+ -- All control frames MUST have a payload length of 125 bytes or less -+ -- and MUST NOT be fragmented. -+ Result.report_error (protocol_error, "Control frame MUST have a payload length of 125 bytes or less") -+ elseif l_len = 127 then -- TODO proof of concept read 8 bytes. -+ -- the following 8 bytes interpreted as a 64-bit unsigned integer -+ -- (the most significant bit MUST be 0) are the payload length. -+ -- Multibyte length quantities are expressed in network byte order. -+ s := next_bytes (l_socket, 8) -- 64 bits -+ debug ("ws") -+ print (" extended payload length=" + string_to_byte_representation (s)) -+ io.put_new_line -+ end -+ if s.count < 8 then -+ Result.report_error (Invalid_data, "Incomplete data for 64 bit Extended payload length") -+ else -+ l_payload_len := s [8].natural_32_code.to_natural_64 -+ l_payload_len := l_payload_len | (s [7].natural_32_code.to_natural_64 |<< 8) -+ l_payload_len := l_payload_len | (s [6].natural_32_code.to_natural_64 |<< 16) -+ l_payload_len := l_payload_len | (s [5].natural_32_code.to_natural_64 |<< 24) -+ l_payload_len := l_payload_len | (s [4].natural_32_code.to_natural_64 |<< 32) -+ l_payload_len := l_payload_len | (s [3].natural_32_code.to_natural_64 |<< 40) -+ l_payload_len := l_payload_len | (s [2].natural_32_code.to_natural_64 |<< 48) -+ l_payload_len := l_payload_len | (s [1].natural_32_code.to_natural_64 |<< 56) -+ end -+ elseif l_len = 126 then -+ s := next_bytes (l_socket, 2) -- 16 bits -+ debug ("ws") -+ print (" extended payload length bits=" + string_to_byte_representation (s)) -+ io.put_new_line -+ end -+ if s.count < 2 then -+ Result.report_error (Invalid_data, "Incomplete data for 16 bit Extended payload length") -+ else -+ l_payload_len := s [2].natural_32_code.to_natural_64 -+ l_payload_len := l_payload_len | (s [1].natural_32_code.to_natural_64 |<< 8) -+ end -+ else -+ l_payload_len := l_len.to_natural_64 -+ end -+ debug ("ws") -+ print (" Full payload length=" + l_payload_len.out) -+ io.put_new_line -+ end -+ if Result.is_valid then -+ if l_has_mask then -+ l_masking_key := next_bytes (l_socket, 4) -- 32 bits -+ debug ("ws") -+ print (" Masking key bits=" + string_to_byte_representation (l_masking_key)) -+ io.put_new_line -+ end -+ if l_masking_key.count < 4 then -+ debug ("ws") -+ print ("masking-key read stream -> " + l_socket.bytes_read.out + " bits%N") -+ end -+ Result.report_error (Invalid_data, "Incomplete data for Masking-key") -+ l_masking_key := Void -+ end -+ else -+ Result.report_error (protocol_error, "All frames sent from client to server are masked!") -+ end -+ if Result.is_valid then -+ l_chunk_size := 0x4000 -- 16 K -+ if l_payload_len > {INTEGER_32}.max_value.to_natural_64 then -+ -- Issue .. to big to store in STRING -+ -- FIXME !!! -+ Result.report_error (Message_too_large, "Can not handle payload data (len=" + l_payload_len.out + ")") -+ else -+ l_len := l_payload_len.to_integer_32 -+ end -+ from -+ l_fetch_count := 0 -+ l_remaining_len := l_len -+ until -+ l_fetch_count >= l_len or l_len = 0 or not Result.is_valid -+ loop -+ if l_remaining_len < l_chunk_size then -+ l_chunk_size := l_remaining_len -+ end -+ l_socket.read_stream (l_chunk_size) -+ l_bytes_read := l_socket.bytes_read -+ debug ("ws") -+ print ("read chunk size=" + l_chunk_size.out + " fetch_count=" + l_fetch_count.out + " l_len=" + l_len.out + " -> " + l_bytes_read.out + "bytes%N") -+ end -+ if l_bytes_read > 0 then -+ l_remaining_len := l_remaining_len - l_bytes_read -+ l_chunk := l_socket.last_string -+ if l_masking_key /= Void then -+ -- Masking -+ -- http://tools.ietf.org/html/rfc6455#section-5.3 -+ unmask (l_chunk, l_fetch_count + 1, l_masking_key) -+ else -+ check -+ client_frame_should_always_be_encoded: False -+ end -+ end -+ l_fetch_count := l_fetch_count + l_bytes_read -+ Result.append_payload_data_chop (l_chunk, l_bytes_read, l_remaining_len = 0) -+ else -+ Result.report_error (internal_error, "Issue reading payload data...") -+ end -+ end -+ if is_verbose then -+ log (" Received " + l_fetch_count.out + " out of " + l_len.out + " bytes <===============", debug_level) -+ end -+ debug ("ws") -+ print (" -> ") -+ if attached Result.payload_data as l_payload_data then -+ s := l_payload_data.tail (l_fetch_count) -+ if s.count > 50 then -+ print (string_to_byte_hexa_representation (s.head (50) + "..")) -+ else -+ print (string_to_byte_hexa_representation (s)) -+ end -+ print ("%N") -+ if Result.is_text and Result.is_fin and Result.fragment_count = 0 then -+ print (" -> ") -+ if s.count > 50 then -+ print (s.head (50) + "..") -+ else -+ print (s) -+ end -+ print ("%N") -+ end -+ end -+ end -+ end -+ end -+ end -+ end -+ end -+ end -+ if Result /= Void then -+ if attached Result.error as err then -+ if is_verbose then -+ log (" !Invalid frame: " + err.string, debug_level) -+ end -+ end -+ if Result.is_injected_control then -+ if attached Result.parent as l_parent then -+ if not Result.is_valid then -+ l_parent.report_error (protocol_error, "Invalid injected frame") -+ end -+ if Result.is_connection_close then -+ -- Return this and process the connection close right away! -+ l_parent.update_fin (True) -+ l_fin := Result.is_fin -+ else -+ Result := l_parent -+ l_fin := l_parent.is_fin -+ check -+ -- This is a control frame but occurs in fragmented frame. -+ inside_fragmented_frame: not l_fin -+ end -+ end -+ else -+ check -+ has_parent: False -+ end -+ l_fin := False -- This is a control frame but occurs in fragmented frame. -+ end -+ end -+ if not Result.is_valid then -+ is_data_frame_ok := False -+ end -+ else -+ is_data_frame_ok := False -+ end -+ end -+ end -+ has_error := Result = Void or else Result.has_error -+ rescue -+ retried := True -+ if Result /= Void then -+ Result.report_error (internal_error, "Internal error") -+ end -+ retry -+ end -+ -+ -+feature -- Encoding -+ -+ digest (a_sha1: SHA1): STRING -+ -- Digest of `a_sha1'. -+ -- Should by in SHA1 class -+ local -+ l_digest: SPECIAL [NATURAL_8] -+ index, l_upper: INTEGER -+ do -+ l_digest := a_sha1.digest -+ create Result.make (l_digest.count // 2) -+ from -+ index := l_digest.Lower -+ l_upper := l_digest.upper -+ until -+ index > l_upper -+ loop -+ Result.append_character (l_digest [index].to_character_8) -+ index := index + 1 -+ end -+ end -+ -+feature {NONE} -- Socket helpers -+ -+ next_bytes (a_socket: HTTPD_STREAM_SOCKET; nb: INTEGER): STRING -+ require -+ nb > 0 -+ local -+ n, l_bytes_read: INTEGER -+ do -+ create Result.make (nb) -+ from -+ n := nb -+ until -+ n = 0 -+ loop -+ a_socket.read_stream (nb) -+ l_bytes_read := a_socket.bytes_read -+ if l_bytes_read > 0 then -+ Result.append (a_socket.last_string) -+ n := n - l_bytes_read -+ else -+ n := 0 -+ end -+ end -+ end -+ -+feature -- Masking Data Client - Server -+ -+ unmask (a_chunk: STRING_8; a_pos: INTEGER; a_key: READABLE_STRING_8) -+ local -+ i, n: INTEGER -+ do -+ from -+ i := 1 -+ n := a_chunk.count -+ until -+ i > n -+ loop -+ a_chunk.put_code (a_chunk.code (i).bit_xor (a_key [((i + (a_pos - 1) - 1) \\ 4) + 1].natural_32_code), i) -+ i := i + 1 -+ end -+ end -+ -+ append_chunk_unmasked (a_chunk: READABLE_STRING_8; a_pos: INTEGER; a_key: READABLE_STRING_8; a_target: STRING) -+ -- To convert masked data into unmasked data, or vice versa, the following -+ -- algorithm is applied. The same algorithm applies regardless of the -+ -- direction of the translation, e.g., the same steps are applied to -+ -- mask the data as to unmask the data. -+ -+ -- Octet i of the transformed data ("transformed-octet-i") is the XOR of -+ -- octet i of the original data ("original-octet-i") with octet at index -+ -- i modulo 4 of the masking key ("masking-key-octet-j"): -+ -+ -- j = i MOD 4 -+ -- transformed-octet-i = original-octet-i XOR masking-key-octet-j -+ -+ -- The payload length, indicated in the framing as frame-payload-length, -+ -- does NOT include the length of the masking key. It is the length of -+ -- the "Payload data", e.g., the number of bytes following the masking -+ -- key. -+ note -+ EIS: "name=Masking", "src=http://tools.ietf.org/html/rfc6455#section-5.3", "protocol=uri" -+ local -+ i, n: INTEGER -+ do -+ -- debug ("ws") -+ -- print ("append_chunk_unmasked (%"" + string_to_byte_representation (a_chunk) + "%",%N%Ta_pos=" + a_pos.out+ ", a_key, a_target #.count=" + a_target.count.out + ")%N") -+ -- end -+ from -+ i := 1 -+ n := a_chunk.count -+ until -+ i > n -+ loop -+ a_target.append_code (a_chunk.code (i).bit_xor (a_key [((i + (a_pos - 1) - 1) \\ 4) + 1].natural_32_code)) -+ i := i + 1 -+ end -+ end -+ -+feature {NONE} -- Debug -+ -+ to_byte_representation (a_integer: INTEGER): STRING -+ require -+ valid: a_integer >= 0 and then a_integer <= 255 -+ local -+ l_val: INTEGER -+ do -+ create Result.make (8) -+ from -+ l_val := a_integer -+ until -+ l_val < 2 -+ loop -+ Result.prepend_integer (l_val \\ 2) -+ l_val := l_val // 2 -+ end -+ Result.prepend_integer (l_val) -+ end -+ -+ string_to_byte_representation (s: STRING): STRING -+ require -+ valid: s.count > 0 -+ local -+ i, n: INTEGER -+ do -+ n := s.count -+ create Result.make (8 * n) -+ if n > 0 then -+ from -+ i := 1 -+ until -+ i > n -+ loop -+ if not Result.is_empty then -+ Result.append_character (':') -+ end -+ Result.append (to_byte_representation (s [i].code)) -+ i := i + 1 -+ end -+ end -+ end -+ -+ string_to_byte_hexa_representation (s: STRING): STRING -+ local -+ i, n: INTEGER -+ c: INTEGER -+ do -+ n := s.count -+ create Result.make (8 * n) -+ if n > 0 then -+ from -+ i := 1 -+ until -+ i > n -+ loop -+ if not Result.is_empty then -+ Result.append_character (':') -+ end -+ c := s [i].code -+ check -+ c <= 0xFF -+ end -+ Result.append_character (((c |>> 4) & 0xF).to_hex_character) -+ Result.append_character (((c) & 0xF).to_hex_character) -+ i := i + 1 -+ end -+ end -+ end -+ -+ -+note -+ 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 -+ 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 -diff --git a/library/server/wsf/connector/standalone_websocket/websocket/web_socket_handler.e b/library/server/wsf/connector/standalone_websocket/websocket/web_socket_handler.e -new file mode 100644 -index 0000000..5268c60 ---- /dev/null -+++ b/library/server/wsf/connector/standalone_websocket/websocket/web_socket_handler.e -@@ -0,0 +1,152 @@ -+note -+ description: "[ -+ To implement websocket handling, provide a `callbacks` object implementing the {WEB_SOCKET_EVENT_I} interface. -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ WEB_SOCKET_HANDLER -+ -+inherit -+ WEB_SOCKET_CONSTANTS -+ -+ REFACTORING_HELPER -+ -+ HTTPD_LOGGER_CONSTANTS -+ -+create -+ make -+ -+feature {NONE} -- Initialization -+ -+ make (ws: WEB_SOCKET; a_callbacks: WEB_SOCKET_EVENT_I) -+ do -+ web_socket := ws -+ callbacks := a_callbacks -+ end -+ -+feature -- Access -+ -+ web_socket: WEB_SOCKET -+ -- Associated websocket. -+ -+ callbacks: WEB_SOCKET_EVENT_I -+ -+feature -- Execution -+ -+ frozen execute -+ do -+ callbacks.on_open (web_socket) -+ execute_websocket -+ end -+ -+ execute_websocket -+ local -+ exit: BOOLEAN -+ l_frame: detachable WEB_SOCKET_FRAME -+ l_client_message: detachable READABLE_STRING_8 -+ l_utf: UTF_CONVERTER -+ ws: like web_socket -+ s: STRING -+ do -+ from -+ -- loop until ws is closed or has error. -+ ws := web_socket -+ until -+ exit -+ loop -+ debug ("dbglog") -+ dbglog (generator + ".execute_websocket (loop) WS_REQUEST_HANDLER.process_request {" + ws.socket_descriptor.out + "}") -+ end -+ if ws.is_ready_for_reading then -+ l_frame := ws.next_frame -+ if l_frame /= Void and then l_frame.is_valid then -+ if attached l_frame.injected_control_frames as l_injections then -+ -- Process injected control frames now. -+ -- FIXME -+ across -+ l_injections as ic -+ loop -+ if ic.item.is_connection_close then -+ -- FIXME: we should probably send this event .. after the `l_frame.parent' frame event. -+ callbacks.on_event (ws, ic.item.payload_data, ic.item.opcode) -+ exit := True -+ elseif ic.item.is_ping then -+ -- FIXME reply only to the most recent ping ... -+ callbacks.on_event (ws, ic.item.payload_data, ic.item.opcode) -+ else -+ callbacks.on_event (ws, ic.item.payload_data, ic.item.opcode) -+ end -+ end -+ end -+ -+ l_client_message := l_frame.payload_data -+ if l_client_message = Void then -+ l_client_message := "" -+ end -+ -+ debug ("ws") -+ create s.make_from_string ("%NExecute: %N") -+ s.append (" [opcode: "+ opcode_name (l_frame.opcode) +"]%N") -+ if l_frame.is_text then -+ s.append (" [client message: %""+ l_client_message +"%"]%N") -+ elseif l_frame.is_binary then -+ s.append (" [client binary message length: %""+ l_client_message.count.out +"%"]%N") -+ end -+ s.append (" [is_control: " + l_frame.is_control.out + "]%N") -+ s.append (" [is_binary: " + l_frame.is_binary.out + "]%N") -+ s.append (" [is_text: " + l_frame.is_text.out + "]%N") -+ dbglog (s) -+ end -+ -+ if l_frame.is_connection_close then -+ callbacks.on_event (ws, l_client_message, l_frame.opcode) -+ exit := True -+ elseif l_frame.is_binary then -+ callbacks.on_event (ws, l_client_message, l_frame.opcode) -+ elseif l_frame.is_text then -+ check is_valid_utf_8: l_utf.is_valid_utf_8_string_8 (l_client_message) end -+ callbacks.on_event (ws, l_client_message, l_frame.opcode) -+ else -+ callbacks.on_event (ws, l_client_message, l_frame.opcode) -+ end -+ else -+ debug ("ws") -+ create s.make_from_string ("%NExecute: %N") -+ s.append (" [ERROR: invalid frame]%N") -+ if l_frame /= Void and then attached l_frame.error as err then -+ s.append (" [Code: "+ err.code.out +"]%N") -+ s.append (" [Description: "+ err.description +"]%N") -+ end -+ dbglog (s) -+ end -+ callbacks.on_event (ws, "", connection_close_frame) -+ exit := True -- FIXME: check proper close protocol -+ end -+ else -+ debug ("ws") -+ dbglog (generator + ".WAITING WS_REQUEST_HANDLER.process_request {" + ws.socket_descriptor.out + "}") -+ end -+ end -+ end -+ end -+ -+feature {NONE} -- Logging -+ -+ dbglog (m: READABLE_STRING_8) -+ do -+ web_socket.log (m, debug_level) -+ end -+ -+note -+ 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 -+ 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 -diff --git a/library/server/wsf/connector/standalone_websocket/wgi_standalone_websocket_connector.e b/library/server/wsf/connector/standalone_websocket/wgi_standalone_websocket_connector.e -new file mode 100644 -index 0000000..1567520 ---- /dev/null -+++ b/library/server/wsf/connector/standalone_websocket/wgi_standalone_websocket_connector.e -@@ -0,0 +1,44 @@ -+note -+ description: "Summary description for {WGI_STANDALONE_WEBSOCKET_CONNECTOR}." -+ author: "" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ WGI_STANDALONE_WEBSOCKET_CONNECTOR [G -> WGI_EXECUTION create make end] -+ -+inherit -+ WGI_STANDALONE_CONNECTOR [G] -+ redefine -+ name, version -+ end -+ -+create -+ make, -+ make_with_base -+ -+feature -- Access -+ -+ name: STRING_8 -+ -- Name of Current connector -+ once -+ Result := "ws_httpd" -+ end -+ -+ version: STRING_8 -+ -- Version of Current connector -+ once -+ Result := "1.0" -+ end -+ -+note -+ 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 -+ 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 -diff --git a/library/server/wsf/connector/standalone_websocket/wsf_standalone_websocket_service_launcher.e b/library/server/wsf/connector/standalone_websocket/wsf_standalone_websocket_service_launcher.e -new file mode 100644 -index 0000000..0a334fb ---- /dev/null -+++ b/library/server/wsf/connector/standalone_websocket/wsf_standalone_websocket_service_launcher.e -@@ -0,0 +1,49 @@ -+note -+ description: "[ -+ Component to launch the service using the default connector -+ -+ Eiffel Web httpd for this class -+ -+ -+ The httpd default connector support options: -+ port: numeric such as 8099 (or equivalent string as "8099") -+ base: base_url (very specific to standalone server) -+ verbose: to display verbose output, useful for standalone connector -+ force_single_threaded: use only one thread, useful for standalone connector -+ -+ check WSF_SERVICE_LAUNCHER for more documentation -+ ]" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ WSF_STANDALONE_WEBSOCKET_SERVICE_LAUNCHER [G -> WSF_WEBSOCKET_EXECUTION create make end] -+ -+inherit -+ WSF_STANDALONE_SERVICE_LAUNCHER [G] -+ redefine -+ connector -+ end -+ -+create -+ make, -+ make_and_launch -+ -+feature -- Status report -+ -+ connector: WGI_STANDALONE_WEBSOCKET_CONNECTOR [G] -+ -- Default connector -+ -+;note -+ 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 -+ 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 -+ -diff --git a/library/server/wsf/connector/standalone_websocket/wsf_websocket_execution.e b/library/server/wsf/connector/standalone_websocket/wsf_websocket_execution.e -new file mode 100644 -index 0000000..78be024 ---- /dev/null -+++ b/library/server/wsf/connector/standalone_websocket/wsf_websocket_execution.e -@@ -0,0 +1,79 @@ -+note -+ description: "[ -+ Request execution based on attributes `request' and `response'. -+ Also support Upgrade to Websocket protocol. -+ -+ -+ ]" -+ author: "$Author$" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ WSF_WEBSOCKET_EXECUTION -+ -+inherit -+ WSF_EXECUTION -+ rename -+ execute as http_execute -+ end -+ -+--create -+-- make -+ -+feature -- Execution -+ -+ frozen http_execute -+ local -+ ws: WEB_SOCKET -+ ws_h: like new_websocket_handler -+ do -+ create ws.make (request, response) -+ ws.open_ws_handshake -+ if ws.is_websocket then -+ if ws.has_error then -+ -- Upgrade to websocket raised an error -+ -- stay on standard HTTP/1.1 protocol -+ execute -+ else -+ ws_h := new_websocket_handler (ws) -+ ws_h.execute -+ end -+ else -+ execute -+ end -+ end -+ -+ execute -+ -- Execute Current request, -+ -- getting data from `request' -+ -- and response to client via `response'. -+ deferred -+ end -+ -+feature -- Factory -+ -+ new_websocket_handler (ws: WEB_SOCKET): WEB_SOCKET_HANDLER -+ -- Websocket request specific handler on socket `ws'. -+ --| For the creation, it requires an instance of `{WEB_SOCKET_EVENT_I}' -+ --| to receive the websocket events. -+ --| One can inherit from {WEB_SOCKET_EVENT_I} and implement the related -+ --| deferred features. -+ --| Or even provide a new class implementing {WEB_SOCKET_EVENT_I}. -+ require -+ is_websocket: ws.is_websocket -+ no_error: not ws.has_error -+ deferred -+ end -+ -+note -+ 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 -+ 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 -diff --git a/library/server/wsf/package.iron b/library/server/wsf/package.iron -index 99d760f..f766b25 100644 ---- a/library/server/wsf/package.iron -+++ b/library/server/wsf/package.iron -@@ -1,13 +1,3 @@ --note -- title: Web Server Foundation -- description: Core of the Eiffel Web Framework, used to build web server application. -- tags: ewf,server,httpd,request,connector -- license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt) -- link[license]: https://github.com/EiffelWebFramework/EWF/blob/master/LICENSE -- link[source]: "Github" https://github.com/EiffelWebFramework/EWF -- link[doc]: "Documentation" http://eiffelwebframework.github.io/EWF/ -- --end - - package wsf - -@@ -37,6 +27,7 @@ project - default_standalone = "default/standalone-safe.ecf" - default_standalone = "default/standalone.ecf" - -+ - note - title: Web Server Foundation - description: "[ -diff --git a/library/server/wsf/src/service/wsf_service_launcher.e b/library/server/wsf/src/service/wsf_service_launcher.e -index 2568a5e..86c41a7 100644 ---- a/library/server/wsf/src/service/wsf_service_launcher.e -+++ b/library/server/wsf/src/service/wsf_service_launcher.e -@@ -22,11 +22,11 @@ note - For instance, you can use - create s.make_and_launch_and_options (agent execute, <<["port", 8099]>>) - -- And if Nino is the default connector it will support: -+ And if the connector is the Standalone connector, -+ check {WSF_STANDALONE_SERVICE_LAUNCHER} for options description, such as: - port: numeric such as 8099 (or equivalent string as "8099") - base: base_url (very specific to standalone server) -- force_single_threaded: use only one thread, useful for Nino -- verbose: to display verbose output, useful for Nino -+ verbose: to display verbose output. - ]" - date: "$Date$" - revision: "$Revision$" -diff --git a/library/server/wsf/src/service/wsf_service_launcher_options.e b/library/server/wsf/src/service/wsf_service_launcher_options.e -index fd690f8..1394c17 100644 ---- a/library/server/wsf/src/service/wsf_service_launcher_options.e -+++ b/library/server/wsf/src/service/wsf_service_launcher_options.e -@@ -8,8 +8,8 @@ note - force_single_threaded: use only one thread, useful for Nino - verbose: to display verbose output, useful for Nino - ]" -- date: "$Date$" -- revision: "$Revision$" -+ date: "$Date: 2016-08-06 13:34:52 +0200 (sam., 06 août 2016) $" -+ revision: "$Revision: 99106 $" - - class - WSF_SERVICE_LAUNCHER_OPTIONS -@@ -83,6 +83,86 @@ feature -- Access - Result := options.item (a_name) - end - -+feature -- Helpers -+ -+ has_option (a_opt_name: READABLE_STRING_GENERAL): BOOLEAN -+ -- Is there any value associated to option name `a_opt_name'? -+ do -+ Result := attached option (a_opt_name) -+ end -+ -+ has_integer_option (a_opt_name: READABLE_STRING_GENERAL): BOOLEAN -+ -- Is there any INTEGER value associated to option name `a_opt_name'? -+ local -+ s: READABLE_STRING_GENERAL -+ do -+ if attached option (a_opt_name) as opt then -+ if attached {INTEGER} opt as i then -+ Result := True -+ else -+ s := opt.out -+ Result := s.is_integer -+ end -+ end -+ end -+ -+ has_string_32_option (a_opt_name: READABLE_STRING_GENERAL): BOOLEAN -+ -- Is there any string 32 value associated to option name `a_opt_name'? -+ do -+ if attached option (a_opt_name) as opt then -+ Result := attached {READABLE_STRING_GENERAL} opt -+ end -+ end -+ -+ option_string_32_value (a_opt_name: READABLE_STRING_GENERAL; a_default: detachable READABLE_STRING_GENERAL): detachable IMMUTABLE_STRING_32 -+ -- Unicode String value associated to option name `a_opt_name', other return `a_default'. -+ do -+ if attached option (a_opt_name) as opt then -+ if attached {READABLE_STRING_32} opt as s32 then -+ create Result.make_from_string (s32) -+ elseif attached {READABLE_STRING_GENERAL} opt as s then -+ create Result.make_from_string_general (s) -+ end -+ end -+ if Result = Void and a_default /= Void then -+ create Result.make_from_string_general (a_default) -+ end -+ end -+ -+ option_integer_value (a_opt_name: READABLE_STRING_GENERAL; a_default: INTEGER): INTEGER -+ -- INTEGER value associated to option name `a_opt_name', other return `a_default'. -+ local -+ s: READABLE_STRING_GENERAL -+ do -+ Result := a_default -+ if attached option (a_opt_name) as opt then -+ if attached {INTEGER} opt as i then -+ Result := i -+ else -+ s := opt.out -+ if s.is_integer then -+ Result := s.to_integer -+ end -+ end -+ end -+ end -+ -+ option_boolean_value (a_opt_name: READABLE_STRING_GENERAL; a_default: BOOLEAN): BOOLEAN -+ -- BOOLEAN value associated to option name `a_opt_name', other return `a_default'. -+ local -+ s: READABLE_STRING_GENERAL -+ do -+ Result := a_default -+ if attached option (a_opt_name) as opt then -+ if attached {BOOLEAN} opt as b then -+ Result := b -+ else -+ s := opt.out -+ Result := s.is_case_insensitive_equal ("true") -+ end -+ end -+ end -+ - feature -- Access - - new_cursor: TABLE_ITERATION_CURSOR [detachable ANY, READABLE_STRING_GENERAL] -diff --git a/library/server/wsf/src/wsf_execution.e b/library/server/wsf/src/wsf_execution.e -index 8bc0a97..352207f 100644 ---- a/library/server/wsf/src/wsf_execution.e -+++ b/library/server/wsf/src/wsf_execution.e -@@ -14,7 +14,6 @@ inherit - make_from_execution as make_from_wgi_execution - redefine - make, -- execute, - clean, - is_valid_end_of_execution - end -diff --git a/library/server/wsf/src/wsf_request.e b/library/server/wsf/src/wsf_request.e -index 055e35b..00708aa 100644 ---- a/library/server/wsf/src/wsf_request.e -+++ b/library/server/wsf/src/wsf_request.e -@@ -261,10 +261,12 @@ feature -- Access: Input - local - l_input: WGI_INPUT_STREAM - n: INTEGER -+ buf_initial_size: INTEGER - do - if raw_input_data_recorded and then attached raw_input_data as d then - buf.append (d) - else -+ buf_initial_size := buf.count - l_input := input - if is_chunked_input then - from -@@ -286,73 +288,53 @@ feature -- Access: Input - end - end - if raw_input_data_recorded then -- set_raw_input_data (buf) -+ set_raw_input_data (buf.substring (buf_initial_size + 1, buf.count)) -+ -- Only the input data! And differente reference. - end - end - end - -- read_input_data_into_file (a_file: FILE) -+ read_input_data_into_file (a_medium: IO_MEDIUM) - -- retrieve the content from the `input' stream into `s' - -- warning: if the input data has already been retrieved - -- you might not get anything - require -- a_file_is_open_write: a_file.is_open_write -+ a_medium_is_open_write: a_medium.is_open_write - local - s: STRING - l_input: WGI_INPUT_STREAM - l_raw_data: detachable STRING_8 -- len: NATURAL_64 - nb, l_step: INTEGER -- l_size: NATURAL_64 - do - if raw_input_data_recorded and then attached raw_input_data as d then -- a_file.put_string (d) -+ a_medium.put_string (d) - else - if raw_input_data_recorded then - create l_raw_data.make_empty - end - l_input := input -- len := content_length_value -- -- debug ("wsf") -- io.error.put_string (generator + ".read_input_data_into_file (a_file) content_length=" + len.out + "%N") -- end - - from -- l_size := 0 - l_step := 8_192 - create s.make (l_step) - until - l_step = 0 or l_input.end_of_input - loop -- if len < l_step.to_natural_64 then -- l_step := len.to_integer_32 -- end -- if l_step > 0 then -- l_input.append_to_string (s, l_step) -- nb := l_input.last_appended_count -- l_size := l_size + nb.to_natural_64 -- len := len - nb.to_natural_64 -- -- debug ("wsf") -- io.error.put_string (" append (s, " + l_step.out + ") -> " + nb.out + " (" + l_size.out + " / "+ content_length_value.out + ")%N") -- end -+ l_input.append_to_string (s, l_step) -+ nb := l_input.last_appended_count - -- a_file.put_string (s) -- if l_raw_data /= Void then -- l_raw_data.append (s) -- end -- s.wipe_out -- if nb < l_step then -- l_step := 0 -- end -+ a_medium.put_string (s) -+ if l_raw_data /= Void then -+ l_raw_data.append (s) -+ end -+ s.wipe_out -+ if nb < l_step then -+ l_step := 0 - end - end -- a_file.flush -- debug ("wsf") -- io.error.put_string ("offset =" + len.out + "%N") -+ if attached {FILE} a_medium as f then -+ f.flush - end -- check got_all_data: len = 0 end - if l_raw_data /= Void then - set_raw_input_data (l_raw_data) - end -diff --git a/library/server/wsf/tests/src/wsf_request_null.e b/library/server/wsf/tests/src/wsf_request_null.e -index 3d6bbea..960cbed 100644 ---- a/library/server/wsf/tests/src/wsf_request_null.e -+++ b/library/server/wsf/tests/src/wsf_request_null.e -@@ -10,7 +10,7 @@ class - inherit - WSF_REQUEST - --create {WSF_TO_WGI_SERVICE, WSF_SERVICE} -+create {WSF_SERVICE} - make_from_wgi - - end -diff --git a/library/server/wsf_proxy/network/no_ssl/wsf_proxy_socket_factory.e b/library/server/wsf_proxy/network/no_ssl/wsf_proxy_socket_factory.e -new file mode 100644 -index 0000000..21c2e7e ---- /dev/null -+++ b/library/server/wsf_proxy/network/no_ssl/wsf_proxy_socket_factory.e -@@ -0,0 +1,20 @@ -+note -+ description: "Summary description for {WSF_PROXY_SOCKET_FACTORY}." -+ author: "" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ WSF_PROXY_SOCKET_FACTORY -+ -+inherit -+ WSF_PROXY_SOCKET_FACTORY_I -+ -+feature {NONE} -- Implementation -+ -+ ssl_socket (a_host: READABLE_STRING_8; a_port: INTEGER): detachable NETWORK_STREAM_SOCKET -+ do -+ check supported: False end -+ end -+ -+end -diff --git a/library/server/wsf_proxy/network/ssl/wsf_proxy_socket_factory.e b/library/server/wsf_proxy/network/ssl/wsf_proxy_socket_factory.e -new file mode 100644 -index 0000000..ad26490 ---- /dev/null -+++ b/library/server/wsf_proxy/network/ssl/wsf_proxy_socket_factory.e -@@ -0,0 +1,30 @@ -+note -+ description: "Summary description for {WSF_PROXY_SOCKET_FACTORY}." -+ author: "" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ WSF_PROXY_SOCKET_FACTORY -+ -+inherit -+ WSF_PROXY_SOCKET_FACTORY_I -+ redefine -+ is_ssl_supported -+ end -+ -+feature {NONE} -- Implementation -+ -+ ssl_socket (a_host: READABLE_STRING_8; a_port: INTEGER): detachable SSL_NETWORK_STREAM_SOCKET -+ do -+ if attached create_from_name (a_host) as l_peer_address then -+ create Result.make_client_by_address_and_port (l_peer_address, a_port) -+ end -+ end -+ -+feature -- Status -+ -+ is_ssl_supported: BOOLEAN = True -+ -- Is https:// supported? -+ -+end -diff --git a/library/server/wsf_proxy/network/wsf_proxy_socket_factory_i.e b/library/server/wsf_proxy/network/wsf_proxy_socket_factory_i.e -new file mode 100644 -index 0000000..900db00 ---- /dev/null -+++ b/library/server/wsf_proxy/network/wsf_proxy_socket_factory_i.e -@@ -0,0 +1,67 @@ -+note -+ description: "Summary description for {WSF_PROXY_SOCKET_FACTORY_I}." -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ WSF_PROXY_SOCKET_FACTORY_I -+ -+inherit -+ INET_ADDRESS_FACTORY -+ -+feature -- Access -+ -+ socket_from_uri (a_uri: URI): like socket -+ local -+ l_port: INTEGER -+ do -+ if a_uri.is_valid and then attached a_uri.host as l_host then -+ l_port := a_uri.port -+ if a_uri.scheme.is_case_insensitive_equal_general ("https") then -+ if is_ssl_supported then -+ if l_port <= 0 then -+ l_port := 443 -+ end -+ Result := ssl_socket (l_host, l_port) -+ end -+ elseif a_uri.scheme.is_case_insensitive_equal_general ("http") then -+ if l_port <= 0 then -+ l_port := 80 -+ end -+ Result := socket (l_host, l_port) -+ end -+ end -+ end -+ -+feature -- Status -+ -+ is_uri_supported (a_uri: URI): BOOLEAN -+ do -+ Result := a_uri.scheme.is_case_insensitive_equal_general ("http") -+ or else ( -+ a_uri.scheme.is_case_insensitive_equal_general ("https") -+ and is_ssl_supported -+ ) -+ end -+ -+ is_ssl_supported: BOOLEAN -+ -- Is https:// supported? -+ do -+ end -+ -+feature {NONE} -- Implementation -+ -+ socket (a_host: READABLE_STRING_8; a_port: INTEGER): detachable NETWORK_STREAM_SOCKET -+ do -+ if attached create_from_name (a_host) as l_peer_address then -+ create Result.make_client_by_address_and_port (l_peer_address, a_port) -+ end -+ end -+ -+ ssl_socket (a_host: READABLE_STRING_8; a_port: INTEGER): detachable NETWORK_STREAM_SOCKET -+ require -+ is_ssl_supported: is_ssl_supported -+ deferred -+ end -+ -+end -diff --git a/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e b/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e -new file mode 100644 -index 0000000..a0ab3c6 ---- /dev/null -+++ b/library/server/wsf_proxy/reverse_proxy/wsf_simple_reverse_proxy_handler.e -@@ -0,0 +1,303 @@ -+note -+ description: "Summary description for {WSF_SIMPLE_REVERSE_PROXY_HANDLER}." -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ WSF_SIMPLE_REVERSE_PROXY_HANDLER -+ -+create -+ make -+ -+feature {NONE} -- Initialization -+ -+ make (a_remote_uri: READABLE_STRING_8) -+ do -+ create remote_uri.make_from_string (a_remote_uri) -+ timeout := 30 -- seconds. See {NETWORK_SOCKET}.default_timeout -+ connect_timeout := 5_000 -- 5 seconds. -+ is_via_header_supported := True -+ end -+ -+feature -- Access -+ -+ remote_uri: URI -+ -- Url for the targetted service. -+ -+ uri_rewriter: detachable WSF_URI_REWRITER assign set_uri_rewriter -+ -- URI rewriter component, to compute the URI on targetted service -+ -- based on current request. -+ -+feature -- Settings -+ -+ connect_timeout: INTEGER assign set_connect_timeout -+ -- In milliseconds. -+ -+ timeout: INTEGER assign set_timeout -+ -- In seconds. -+ -+ is_via_header_supported: BOOLEAN -+ -- Via: header supported. -+ -- Default: True. -+ -+feature -- Change -+ -+ set_uri_rewriter (a_rewriter: like uri_rewriter) -+ do -+ uri_rewriter := a_rewriter -+ end -+ -+ set_timeout (a_timeout_in_seconds: INTEGER) -+ -- in seconds. -+ do -+ timeout := a_timeout_in_seconds -+ end -+ -+ set_connect_timeout (a_timeout_in_milliseconds: INTEGER) -+ -- in milliseconds. -+ do -+ connect_timeout := a_timeout_in_milliseconds -+ end -+ -+ set_is_via_header_supported (b: BOOLEAN) -+ -- Set `is_via_header_supported' to `b'. -+ do -+ is_via_header_supported := b -+ end -+ -+feature -- Execution -+ -+ proxy_uri (request: WSF_REQUEST): STRING -+ -- URI to query on proxyfied host. -+ do -+ if attached uri_rewriter as r then -+ Result := r.uri (request) -+ else -+ Result := request.request_uri -+ end -+ end -+ -+ execute (request: WSF_REQUEST; response: WSF_RESPONSE) -+ -- Execute reverse proxy request. -+ local -+ h: HTTP_HEADER -+ l_http_query: STRING -+ l_status_line: STRING -+ l_max_forward: INTEGER -+ l_via: detachable STRING -+ l_protocol: STRING -+ i: INTEGER -+ l_completed: BOOLEAN -+ l_remote_uri: like remote_uri -+ l_socket_factory: WSF_PROXY_SOCKET_FACTORY -+ do -+ l_remote_uri := remote_uri -+ create l_socket_factory -+ if not l_socket_factory.is_uri_supported (l_remote_uri) then -+ send_error (request, response, {HTTP_STATUS_CODE}.bad_gateway, l_remote_uri.scheme + " is not supported! [for remote " + l_remote_uri.string + "]") -+ elseif attached l_socket_factory.socket_from_uri (l_remote_uri) as l_socket then -+ l_socket.set_connect_timeout (connect_timeout) -- milliseconds -+ l_socket.set_timeout (timeout) -- seconds -+ -+ l_socket.connect -+ if l_socket.is_connected then -+ create l_http_query.make_from_string (request.request_method) -+ l_http_query.append_character (' ') -+ l_http_query.append (l_remote_uri.path) -+ l_http_query.append (proxy_uri (request)) -+ l_http_query.append_character (' ') -+ l_http_query.append (request.server_protocol) -+ if attached request.raw_header_data as l_raw_header then -+ i := l_raw_header.substring_index ("%R%N", 1) -+ if i > 0 then -+ -- Skip the first status line. -+ create h.make_from_raw_header_data (l_raw_header.substring (i + 2, l_raw_header.count)) -+ else -+ create h.make_from_raw_header_data (l_raw_header) -+ end -+ if attached l_remote_uri.host as l_remote_host then -+ if l_remote_uri.port > 0 then -+ h.put_header_key_value ("Host", l_remote_host + ":" + l_remote_uri.port.out) -+ else -+ h.put_header_key_value ("Host", l_remote_host) -+ end -+ end -+ -+ -- Via header -+ if is_via_header_supported then -+ if attached h.item ("Via") as v then -+ l_via := v -+ l_via.append (", ") -+ else -+ create l_via.make_empty -+ end -+ l_via.append (request.server_protocol + " " + request.server_name + " (PROXY-" + request.server_software + ")") -+ h.put_header_key_value ("Via", l_via) -+ end -+ -+ -- Max-Forwards header handling -+ if attached h.item ("Max-Forwards") as h_max_forward then -+ -- Max-Forwards: 0 stop, otherwise decrement by one. -+ -- see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.31 -+ if h_max_forward.is_integer then -+ l_max_forward := h_max_forward.to_integer - 1 -+ if l_max_forward >= 0 then -+ h.put_header_key_value ("Max-Forwards", l_max_forward.out) -+ end -+ end -+ end -+ if l_max_forward < 0 then -+ -- i.e previous Max-Forwards was '0' -+ send_error (request, response, {HTTP_STATUS_CODE}.bad_gateway, "Reached maximum number of Forwards, not forwarded to " + l_remote_uri.string) -+ else -+ l_socket.put_string (l_http_query) -+ l_socket.put_string ("%R%N") -+ l_socket.put_string (h.string) -+ l_socket.put_string ("%R%N") -+ if request.content_length_value > 0 then -+ request.read_input_data_into_file (l_socket) -+ end -+ -+ -- Get HTTP status -+ l_socket.read_line_thread_aware -+ create l_status_line.make_from_string (l_socket.last_string) -+ -- Get HTTP header block -+ if attached next_http_header_block (l_socket) as l_resp_header then -+ create h.make_from_raw_header_data (l_resp_header) -+ if attached status_line_info (l_status_line) as l_status_info then -+ l_protocol := l_status_info.protocol -+ if attached l_status_info.reason_phrase as l_phrase then -+ response.set_status_code_with_reason_phrase (l_status_info.status_code, l_phrase) -+ else -+ response.set_status_code (l_status_info.status_code) -+ end -+ else -+ check has_status_line: False end -+ l_protocol := "1.0" -- Default? -+ response.set_status_code (80) -+ end -+ -+ if is_via_header_supported then -+ if attached h.item ("Via") as v then -+ l_via := v -+ l_via.append (", ") -+ else -+ create l_via.make_empty -+ end -+ l_via.append (l_protocol + " " + request.server_name + " (PROXY-" + request.server_software + ")") -+ h.put_header_key_value ("Via", l_via) -+ end -+ -+ response.add_header_lines (h) -+ from -+ l_socket.read_stream (2_048) -+ until -+ l_socket.was_error -+ or not l_socket.is_connected -+ or l_socket.bytes_read <= 0 -+ or l_completed -+ loop -+ response.put_string (l_socket.last_string) -+ if l_socket.bytes_read = 2_048 then -+ l_socket.read_stream (2_048) -+ else -+ l_completed := True -+ end -+ end -+ else -+ send_error (request, response, {HTTP_STATUS_CODE}.internal_server_error, "Invalid response header!") -+ end -+ end -+ else -+ send_error (request, response, {HTTP_STATUS_CODE}.internal_server_error, "Can not access request header!") -+ end -+ else -+ send_error (request, response, {HTTP_STATUS_CODE}.gateway_timeout, "Unable to connect " + l_remote_uri.string) -+ end -+ else -+ send_error (request, response, {HTTP_STATUS_CODE}.bad_gateway, "Unable to connect " + l_remote_uri.string) -+ end -+ end -+ -+feature {NONE} -- Implementation -+ -+ status_line_info (a_line: READABLE_STRING_8): detachable TUPLE [protocol: READABLE_STRING_8; status_code: INTEGER; reason_phrase: detachable READABLE_STRING_8] -+ -- Info from status line -+ --| Such as "HTTP/1.1 200 OK" -> ["1.1", 200, "OK"] -+ local -+ i,j: INTEGER -+ p,s: detachable READABLE_STRING_8 -+ c: INTEGER -+ do -+ i := a_line.index_of (' ', 1) -+ if i > 0 then -+ p := a_line.substring (1, i - 1) -+ if p.starts_with_general ("HTTP/") then -+ p := p.substring (6, p.count) -- We could also keep HTTP/ -+ end -+ j := i + 1 -+ i := a_line.index_of (' ', j) -+ if i > 0 then -+ s := a_line.substring (j, i - 1) -+ if s.is_integer then -+ c := s.to_integer -+ s := a_line.substring (i + 1, a_line.count) -+ if s.is_whitespace then -+ s := Void -+ elseif s[s.count].is_space then -+ s := s.substring (1, s.count - 1) -+ end -+ Result := [p, c, s] -+ end -+ end -+ end -+ end -+ -+ next_http_header_block (a_socket: NETWORK_STREAM_SOCKET): detachable STRING -+ local -+ h: STRING -+ do -+ create h.make_empty -+ from -+ a_socket.read_line_thread_aware -+ until -+ Result /= Void -+ or a_socket.was_error -+ or (a_socket.bytes_read = 0 or a_socket.bytes_read = -1) -+ or not a_socket.is_connected -+ loop -+ if a_socket.last_string.same_string ("%R") then -+ -- End of header -+ Result := h -+ else -+ h.append (a_socket.last_string) -+ h.append ("%N") -+ a_socket.read_line_thread_aware -+ end -+ end -+ end -+ -+ send_error (request: WSF_REQUEST; response: WSF_RESPONSE; a_status_code: INTEGER; a_message: READABLE_STRING_8) -+ local -+ s: STRING -+ do -+ -- To send a response we need to setup, the status code and -+ -- the response headers. -+ create s.make_from_string (a_message) -+ debug -+ s.append ("%N(UTC time is " + (create {HTTP_DATE}.make_now_utc).rfc850_string + ").%N") -+ end -+ response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "plain/text"], ["Content-Length", s.count.out]>>) -+ response.set_status_code (a_status_code) -+ 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 -diff --git a/library/server/wsf_proxy/rewriter/wsf_agent_uri_rewriter.e b/library/server/wsf_proxy/rewriter/wsf_agent_uri_rewriter.e -new file mode 100644 -index 0000000..fc054b3 ---- /dev/null -+++ b/library/server/wsf_proxy/rewriter/wsf_agent_uri_rewriter.e -@@ -0,0 +1,38 @@ -+note -+ description: "Summary description for {WSF_AGENT_URI_REWRITER}." -+ author: "" -+ date: "$Date$" -+ revision: "$Revision$" -+ -+class -+ WSF_AGENT_URI_REWRITER -+ -+inherit -+ WSF_URI_REWRITER -+ -+create -+ make -+ -+--convert -+-- make ({FUNCTION [TUPLE [WSF_REQUEST], STRING]}) -+ -+feature {NONE} -- Initialization -+ -+ make (a_rewriter_function: like rewriter_function) -+ do -+ rewriter_function := a_rewriter_function -+ end -+ -+feature -- Access -+ -+ rewriter_function: FUNCTION [TUPLE [WSF_REQUEST], STRING] -+ -+feature -- Conversion -+ -+ uri (a_request: WSF_REQUEST): STRING -+ -- . -+ do -+ Result := rewriter_function (a_request) -+ end -+ -+end -diff --git a/library/server/wsf_proxy/rewriter/wsf_uri_rewriter.e b/library/server/wsf_proxy/rewriter/wsf_uri_rewriter.e -new file mode 100644 -index 0000000..6cbc1ca ---- /dev/null -+++ b/library/server/wsf_proxy/rewriter/wsf_uri_rewriter.e -@@ -0,0 +1,16 @@ -+note -+ description: "Summary description for {WSF_URI_REWRITER}." -+ date: "$Date$" -+ revision: "$Revision$" -+ -+deferred class -+ WSF_URI_REWRITER -+ -+feature -- Conversion -+ -+ uri (a_request: WSF_REQUEST): STRING -+ -- Rewritten request uri based on `a_request'. -+ deferred -+ end -+ -+end -diff --git a/library/server/wsf_proxy/wsf_proxy-safe.ecf b/library/server/wsf_proxy/wsf_proxy-safe.ecf -new file mode 100644 -index 0000000..9dd777c ---- /dev/null -+++ b/library/server/wsf_proxy/wsf_proxy-safe.ecf -@@ -0,0 +1,34 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ no_ssl -+ ssl -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/library/server/wsf_proxy/wsf_proxy.ecf b/library/server/wsf_proxy/wsf_proxy.ecf -new file mode 100644 -index 0000000..17ffa57 ---- /dev/null -+++ b/library/server/wsf_proxy/wsf_proxy.ecf -@@ -0,0 +1,36 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ no_ssl -+ ssl -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/library/text/parser/feed/feed-safe.ecf b/library/text/parser/feed/feed-safe.ecf -index 3c5a7dd..48591ec 100644 ---- a/library/text/parser/feed/feed-safe.ecf -+++ b/library/text/parser/feed/feed-safe.ecf -@@ -5,7 +5,7 @@ - - - -- -+ - - - -diff --git a/library/text/parser/feed/feed.ecf b/library/text/parser/feed/feed.ecf -index a69dd4e..9d4031e 100644 ---- a/library/text/parser/feed/feed.ecf -+++ b/library/text/parser/feed/feed.ecf -@@ -7,7 +7,7 @@ - - - -- -+ - - - -diff --git a/library/text/parser/feed/src/atom/atom_feed_generator.e b/library/text/parser/feed/src/atom/atom_feed_generator.e -index 4f15a22..f4d8791 100644 ---- a/library/text/parser/feed/src/atom/atom_feed_generator.e -+++ b/library/text/parser/feed/src/atom/atom_feed_generator.e -@@ -72,6 +72,13 @@ feature -- Visitor - if attached a_entry.date as dt then - append_content_tag_to ("updated", Void, date_to_string (dt), buffer) - end -+ if attached a_entry.categories as cats then -+ across -+ cats as ic -+ loop -+ append_content_tag_to ("category", <<["term", ic.item]>>, Void, buffer) -+ end -+ end - - append_content_tag_to ("summary", Void, a_entry.description, buffer) - if attached a_entry.content as l_content then -diff --git a/library/text/parser/feed/src/atom/atom_feed_parser.e b/library/text/parser/feed/src/atom/atom_feed_parser.e -index d486598..0c16b2c 100644 ---- a/library/text/parser/feed/src/atom/atom_feed_parser.e -+++ b/library/text/parser/feed/src/atom/atom_feed_parser.e -@@ -81,6 +81,7 @@ feature -- Access - if attached x_entry.element_by_name ("content") as x_content then - e.set_content (xml_element_code (x_content), xml_attribute_text (x_content, "type")) - end -+ - if attached x_entry.element_by_name ("author") as x_author then - if attached x_author.element_by_name ("name") as x_name and then - attached x_name.text as l_author_name -@@ -92,6 +93,17 @@ feature -- Access - e.set_author (l_author) - end - end -+ -+ -- Optional "category" -+ if attached x_entry.elements_by_name ("category") as x_categories then -+ across -+ x_categories as cats_ic -+ loop -+ if attached xml_attribute_text (cats_ic.item, "term") as l_term then -+ e.set_category (l_term) -+ end -+ end -+ end - Result.extend (e) - end - end -diff --git a/library/text/parser/feed/src/support/feed_generator.e b/library/text/parser/feed/src/support/feed_generator.e -index efbb8b8..cad90cc 100644 ---- a/library/text/parser/feed/src/support/feed_generator.e -+++ b/library/text/parser/feed/src/support/feed_generator.e -@@ -66,7 +66,7 @@ feature {NONE} -- Helpers - end - end - if a_content = Void then -- a_output.append ("/>") -+ a_output.append ("/>%N") - else - a_output.append (">") - a_output.append (escaped_unicode_xml (a_content.as_string_32)) -diff --git a/library/text/parser/feed/tests/atom_test_set.e b/library/text/parser/feed/tests/atom_test_set.e -index 68eab06..1ffaa2f 100644 ---- a/library/text/parser/feed/tests/atom_test_set.e -+++ b/library/text/parser/feed/tests/atom_test_set.e -@@ -65,6 +65,7 @@ feature {NONE} -- Data - John Doe - johndoe@example.com - -+ - - - -diff --git a/library/text/parser/feed/tests/msys-iconv-2.dll b/library/text/parser/feed/tests/msys-iconv-2.dll -new file mode 100644 -index 0000000..111ded9 -Binary files /dev/null and b/library/text/parser/feed/tests/msys-iconv-2.dll differ -diff --git a/library/text/parser/feed/tests/tests-safe.ecf b/library/text/parser/feed/tests/tests-safe.ecf -index 6620d47..abc3309 100644 ---- a/library/text/parser/feed/tests/tests-safe.ecf -+++ b/library/text/parser/feed/tests/tests-safe.ecf -@@ -6,7 +6,7 @@ - - - -- -+ - - - -diff --git a/tests/all-safe.ecf b/tests/all-safe.ecf -index 0516825..727ff92 100644 ---- a/tests/all-safe.ecf -+++ b/tests/all-safe.ecf -@@ -17,6 +17,7 @@ - - - -+ - - - -@@ -30,6 +31,7 @@ - - - -+ - - - -diff --git a/tests/dev/hello-safe.ecf b/tests/dev/hello-safe.ecf -index 94095cc..e61bc49 100644 ---- a/tests/dev/hello-safe.ecf -+++ b/tests/dev/hello-safe.ecf -@@ -1,14 +1,15 @@ - - - -- -+ - - /EIFGENs$ - /\.git$ - /\.svn$ - - - -@@ -16,20 +17,20 @@ - - - -- -+ - -- -+ - - - -- -+ - - - -- -+ - - - -diff --git a/tests/dev/src/hello_routed_world.e b/tests/dev/src/hello_routed_world.e -index fa588fe..f0d3a62 100644 ---- a/tests/dev/src/hello_routed_world.e -+++ b/tests/dev/src/hello_routed_world.e -@@ -8,243 +8,24 @@ class - HELLO_ROUTED_WORLD - - inherit -- WSF_URI_TEMPLATE_ROUTED_SERVICE -- -- WSF_HANDLER_HELPER -- -- WSF_DEFAULT_SERVICE -+ WSF_DEFAULT_SERVICE [HELLO_ROUTED_WORLD_EXECUTION] -+ redefine -+ initialize -+ end - - create -- make -+ make_and_launch - - feature {NONE} -- Initialization - -- make -+ initialize - do -- initialize_router -+ Precursor - set_service_option ("port", 8099) -- make_and_launch -- end -- -- create_router -- do -- create router.make (5) -- end -- -- setup_router -- local -- ra: WSF_AGENT_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT] -- hello: WSF_URI_TEMPLATE_ROUTING_HANDLER -- www: WSF_FILE_SYSTEM_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT] -- do -- router.map_agent ("/refresh", agent execute_refresh) -- router.map_agent ("/home", agent execute_home) -- create www.make (document_root) -- www.set_directory_index (<<"index.html">>) -- -- router.map ("/www{/path}{?query}", www) -- -- --| Map all "/hello*" using a ROUTING_HANDLER -- create hello.make (3) -- router.map ("/hello", hello) -- -- create ra.make (agent handle_hello) -- hello.map ("/hello/{name}.{format}", ra) -- hello.map ("/hello.{format}/{name}", ra) -- hello.map ("/hello/{name}", ra) -- -- create ra.make (agent handle_anonymous_hello) -- hello.map ("/hello", ra) -- hello.map ("/hello.{format}", ra) -- -- --| Various various route, directly on the "router" -- router.map_agent_with_request_methods ("/method/any", agent handle_method_any, Void) -- router.map_agent_with_request_methods ("/method/guess", agent handle_method_get_or_post, <<"GET", "POST">>) -- router.map_agent_with_request_methods ("/method/custom", agent handle_method_get, <<"GET">>) -- router.map_agent_with_request_methods ("/method/custom", agent handle_method_post, <<"POST">>) -- end -- -- -- document_root: READABLE_STRING_8 -- local -- e: EXECUTION_ENVIRONMENT -- dn: DIRECTORY_NAME -- once -- create e -- create dn.make_from_string (e.current_working_directory) -- dn.extend ("htdocs") -- Result := dn.string -- if Result[Result.count] = Operating_environment.directory_separator then -- Result := Result.substring (1, Result.count - 1) -- end -- end -- --feature -- Execution -- -- -- execute_default (req: WSF_REQUEST; res: WSF_RESPONSE) -- local -- l_url: STRING -- do -- l_url := req.absolute_script_url ("/home") -- res.redirect_now_with_content (l_url, "You are now being redirected to " + l_url, {HTTP_MIME_TYPES}.text_html) -- end -- -- execute_refresh (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE) -- local -- h: HTTP_HEADER -- l_url: STRING -- e: EXECUTION_ENVIRONMENT -- n: INTEGER -- i: INTEGER -- s: STRING_8 -- do -- l_url := req.absolute_script_url ("/home") -- -- -- -- n := 3 -- create h.make -- h.put_refresh (l_url, 5) -- h.put_location (l_url) -- h.put_content_type_text_plain -- h.put_transfer_encoding_chunked ---- h.put_content_length (0) ---- res.set_status_code ({HTTP_STATUS_CODE}.moved_permanently) -- res.set_status_code ({HTTP_STATUS_CODE}.ok) -- res.put_header_text (h.string) -- -- from -- create e -- create s.make (255) -- until -- n = 0 -- loop -- if n > 1 then -- s.append ("%NRedirected to " + l_url + " in " + n.out + " seconds :%N") -- else -- s.append ("%NRedirected to " + l_url + " in 1 second :%N") -- end -- res.put_chunk (s, Void); s.wipe_out -- from -- i := 1 -- until -- i = 1001 -- loop -- s.append_character ('.') -- if i \\ 100 = 0 then -- s.append_character ('%N') -- end -- res.put_chunk (s, Void); s.wipe_out -- e.sleep (1_000_000) -- i := i + 1 -- end -- n := n - 1 -- end -- s.append ("%NYou are now being redirected...%N") -- res.put_chunk (s, Void); s.wipe_out -- res.put_chunk_end - end - -- execute_home (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE) -- local -- l_body: STRING_8 -- do -- create l_body.make (255) -- l_body.append ("Hello World ?!%N") -- l_body.append ("

Please try the following links

%N") -- if attached req.item ("REQUEST_COUNT") as rqc then -- l_body.append ("request #"+ rqc.as_string.string + "%N") -- end -- l_body.append ("%N") -- -- res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_body.count.out]>>) -- res.put_string (l_body) -- end -- -- execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE; a_name: detachable READABLE_STRING_32; ctx: WSF_HANDLER_CONTEXT) -- local -- l_response_content_type: detachable STRING -- h: HTTP_HEADER -- content_type_supported: ARRAY [STRING] -- l_body: STRING_8 -- do -- if a_name /= Void then -- l_body := "Hello %"" + a_name + "%" !%N" -- else -- l_body := "Hello anonymous visitor !%N" -- end -- content_type_supported := <<{HTTP_MIME_TYPES}.application_json, {HTTP_MIME_TYPES}.text_html, {HTTP_MIME_TYPES}.text_xml, {HTTP_MIME_TYPES}.text_plain>> -- inspect ctx.request_format_id ("format", content_type_supported) -- when {HTTP_FORMAT_CONSTANTS}.json then -- l_response_content_type := {HTTP_MIME_TYPES}.application_json -- l_body := "{%N%"application%": %"/hello%",%N %"message%": %"" + l_body + "%" %N}" -- when {HTTP_FORMAT_CONSTANTS}.html then -- l_response_content_type := {HTTP_MIME_TYPES}.text_html -- when {HTTP_FORMAT_CONSTANTS}.xml then -- l_response_content_type := {HTTP_MIME_TYPES}.text_xml -- l_body := "/hello" + l_body + "%N" -- when {HTTP_FORMAT_CONSTANTS}.text then -- l_response_content_type := {HTTP_MIME_TYPES}.text_plain -- else -- execute_content_type_not_allowed (req, res, content_type_supported, -- <<{HTTP_FORMAT_CONSTANTS}.json_name, {HTTP_FORMAT_CONSTANTS}.html_name, {HTTP_FORMAT_CONSTANTS}.xml_name, {HTTP_FORMAT_CONSTANTS}.text_name>> -- ) -- end -- if l_response_content_type /= Void then -- create h.make -- h.put_content_type (l_response_content_type) -- h.put_content_length (l_body.count) -- res.set_status_code ({HTTP_STATUS_CODE}.ok) -- res.put_header_text (h.string) -- res.put_string (l_body) -- end -- end -- -- handle_hello (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE) -- do -- execute_hello (req, res, ctx.string_parameter ("name"), ctx) -- end -- -- handle_anonymous_hello (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE) -- do -- execute_hello (req, res, ctx.string_parameter ("name"), ctx) -- end -- -- handle_method_any (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE) -- do -- execute_hello (req, res, req.request_method, ctx) -- end -- -- handle_method_get (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE) -- do -- execute_hello (req, res, "GET", ctx) -- end -- -- -- handle_method_post (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE) -- do -- execute_hello (req, res, "POST", ctx) -- end -- -- handle_method_get_or_post (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE) -- do -- execute_hello (req, res, "GET or POST", ctx) -- end -- -- -- - note -- copyright: "2011-2011, Eiffel Software and others" -+ copyright: "2011-2016, Eiffel Software and others" - license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" - source: "[ - Eiffel Software -diff --git a/tests/dev/src/hello_routed_world_execution.e b/tests/dev/src/hello_routed_world_execution.e -new file mode 100644 -index 0000000..6dd3e6d ---- /dev/null -+++ b/tests/dev/src/hello_routed_world_execution.e -@@ -0,0 +1,272 @@ -+note -+ description : "Objects that ..." -+ author : "$Author$" -+ date : "$Date$" -+ revision : "$Revision$" -+ -+class -+ HELLO_ROUTED_WORLD_EXECUTION -+ -+inherit -+ WSF_ROUTED_EXECUTION -+ redefine -+ execute_default -+ end -+ -+ WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_EXECUTION -+ -+create -+ make -+ -+feature {NONE} -- Initialization -+ -+ setup_router -+ local -+ ra: WSF_URI_TEMPLATE_AGENT_HANDLER -+ hello: WSF_URI_TEMPLATE_ROUTING_HANDLER -+ www: WSF_FILE_SYSTEM_HANDLER -+ do -+ map_uri_template_agent ("/refresh", agent execute_refresh, Void) -+ map_uri_template_agent ("/home", agent execute_home, Void) -+ create www.make (document_root) -+ www.set_directory_index (<<"index.html">>) -+ router.handle ("/www{/path}{?query}", www, Void) -+ -+ --| Map all "/hello*" using a ROUTING_HANDLER -+ create hello.make (3) -+ router.handle ("/hello", hello, Void) -+ -+ create ra.make (agent handle_hello) -+ hello.router.handle ("/hello/{name}.{format}", ra, Void) -+ hello.router.handle ("/hello.{format}/{name}", ra, Void) -+ hello.router.handle ("/hello/{name}", ra, Void) -+ -+ create ra.make (agent handle_anonymous_hello) -+ hello.router.handle ("/hello", ra, Void) -+ hello.router.handle ("/hello.{format}", ra, Void) -+ -+ --| Various various route, directly on the "router" -+ map_uri_template_agent ("/method/any", agent handle_method_any, Void) -+ map_uri_template_agent ("/method/guess", agent handle_method_get_or_post, <<"GET", "POST">>) -+ map_uri_template_agent ("/method/custom", agent handle_method_get, <<"GET">>) -+ map_uri_template_agent ("/method/custom", agent handle_method_post, <<"POST">>) -+ end -+ -+ -+ document_root: READABLE_STRING_8 -+ local -+ e: EXECUTION_ENVIRONMENT -+ dn: DIRECTORY_NAME -+ once -+ create e -+ create dn.make_from_string (e.current_working_directory) -+ dn.extend ("htdocs") -+ Result := dn.string -+ if Result[Result.count] = Operating_environment.directory_separator then -+ Result := Result.substring (1, Result.count - 1) -+ end -+ end -+ -+feature -- Execution -+ -+ -+ execute_default (req: WSF_REQUEST; res: WSF_RESPONSE) -+ local -+ l_url: STRING -+ do -+ l_url := req.absolute_script_url ("/home") -+ res.redirect_now_with_content (l_url, "You are now being redirected to " + l_url, {HTTP_MIME_TYPES}.text_html) -+ end -+ -+ execute_refresh (req: WSF_REQUEST; res: WSF_RESPONSE) --ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; -+ local -+ h: HTTP_HEADER -+ l_url: STRING -+ e: EXECUTION_ENVIRONMENT -+ n: INTEGER -+ i: INTEGER -+ s: STRING_8 -+ do -+ l_url := req.absolute_script_url ("/home") -+ -+ -+ -+ n := 3 -+ create h.make -+ h.put_refresh (l_url, 5) -+ h.put_location (l_url) -+ h.put_content_type_text_plain -+ h.put_transfer_encoding_chunked -+-- h.put_content_length (0) -+-- res.set_status_code ({HTTP_STATUS_CODE}.moved_permanently) -+ res.set_status_code ({HTTP_STATUS_CODE}.ok) -+ res.put_header_text (h.string) -+ -+ from -+ create e -+ create s.make (255) -+ until -+ n = 0 -+ loop -+ if n > 1 then -+ s.append ("%NRedirected to " + l_url + " in " + n.out + " seconds :%N") -+ else -+ s.append ("%NRedirected to " + l_url + " in 1 second :%N") -+ end -+ res.put_chunk (s, Void); s.wipe_out -+ from -+ i := 1 -+ until -+ i = 1001 -+ loop -+ s.append_character ('.') -+ if i \\ 100 = 0 then -+ s.append_character ('%N') -+ end -+ res.put_chunk (s, Void); s.wipe_out -+ e.sleep (1_000_000) -+ i := i + 1 -+ end -+ n := n - 1 -+ end -+ s.append ("%NYou are now being redirected...%N") -+ res.put_chunk (s, Void); s.wipe_out -+ res.put_chunk_end -+ end -+ -+ execute_home (req: WSF_REQUEST; res: WSF_RESPONSE) -- ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; -+ local -+ l_body: STRING_8 -+ do -+ create l_body.make (255) -+ l_body.append ("Hello World ?!%N") -+ l_body.append ("

Please try the following links

%N") -+ if attached req.item ("REQUEST_COUNT") as rqc then -+ l_body.append ("request #"+ rqc.as_string.url_encoded_value + "%N") -+ end -+ l_body.append ("%N") -+ -+ res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", l_body.count.out]>>) -+ res.put_string (l_body) -+ end -+ -+ execute_hello (req: WSF_REQUEST; res: WSF_RESPONSE; a_name: detachable READABLE_STRING_32) -+ local -+ l_response_content_type: detachable STRING -+ h: HTTP_HEADER -+ content_type_supported: ARRAY [STRING] -+ l_body: STRING_8 -+ l_format: detachable READABLE_STRING_GENERAL -+ l_http_format_constants: HTTP_FORMAT_CONSTANTS -+ do -+ if a_name /= Void then -+ l_body := "Hello %"" + a_name + "%" !%N" -+ else -+ l_body := "Hello anonymous visitor !%N" -+ end -+ content_type_supported := <<{HTTP_MIME_TYPES}.application_json, {HTTP_MIME_TYPES}.text_html, {HTTP_MIME_TYPES}.text_xml, {HTTP_MIME_TYPES}.text_plain>> -+ if attached {WSF_STRING} req.path_parameter ("format") as s_format then -+ l_format := s_format.value -+ end -+ if l_format = Void then -+ across -+ content_type_supported as ic -+ until -+ l_format /= Void -+ loop -+ if req.is_content_type_accepted (ic.item) then -+ l_format := ic.item -+ end -+ end -+ end -+ if l_format /= Void then -+ create l_http_format_constants -+ inspect -+ l_http_format_constants.format_id (l_format) -+ when {HTTP_FORMAT_CONSTANTS}.json then -+ l_response_content_type := {HTTP_MIME_TYPES}.application_json -+ l_body := "{%N%"application%": %"/hello%",%N %"message%": %"" + l_body + "%" %N}" -+ when {HTTP_FORMAT_CONSTANTS}.html then -+ l_response_content_type := {HTTP_MIME_TYPES}.text_html -+ when {HTTP_FORMAT_CONSTANTS}.xml then -+ l_response_content_type := {HTTP_MIME_TYPES}.text_xml -+ l_body := "/hello" + l_body + "%N" -+ when {HTTP_FORMAT_CONSTANTS}.text then -+ l_response_content_type := {HTTP_MIME_TYPES}.text_plain -+ else -+ l_response_content_type := Void -+ end -+ end -+ -+ if l_response_content_type /= Void then -+ create h.make -+ h.put_content_type (l_response_content_type) -+ h.put_content_length (l_body.count) -+ res.set_status_code ({HTTP_STATUS_CODE}.ok) -+ res.put_header_text (h.string) -+ res.put_string (l_body) -+ else -+ res.send (create {WSF_PRECONDITION_FAILED_MESSAGE}.make (req)) -- FIXME: better error message! -+ end -+ end -+ -+ string_path_parameter (req: WSF_REQUEST; a_name: READABLE_STRING_GENERAL): detachable STRING_32 -+ do -+ if attached {WSF_STRING} req.path_parameter (a_name) as s then -+ Result := s.value -+ end -+ end -+ -+ handle_hello (req: WSF_REQUEST; res: WSF_RESPONSE) -+ do -+ execute_hello (req, res, string_path_parameter (req, "name")) -+ end -+ -+ handle_anonymous_hello (req: WSF_REQUEST; res: WSF_RESPONSE) -+ do -+ execute_hello (req, res, string_path_parameter (req, "name")) -+ end -+ -+ handle_method_any (req: WSF_REQUEST; res: WSF_RESPONSE) -+ do -+ execute_hello (req, res, req.request_method) -+ end -+ -+ handle_method_get (req: WSF_REQUEST; res: WSF_RESPONSE) -+ do -+ execute_hello (req, res, "GET") -+ end -+ -+ -+ handle_method_post (req: WSF_REQUEST; res: WSF_RESPONSE) -+ do -+ execute_hello (req, res, "POST") -+ end -+ -+ handle_method_get_or_post (req: WSF_REQUEST; res: WSF_RESPONSE) -+ do -+ execute_hello (req, res, "GET or POST") -+ end -+ -+ -+ -+note -+ copyright: "2011-2016, 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 -diff --git a/tools/install_ewf.bat b/tools/install_ewf.bat -index ae26e20..dd1fa88 100644 ---- a/tools/install_ewf.bat -+++ b/tools/install_ewf.bat -@@ -59,6 +59,8 @@ echo Install library: ewf/wsf - %COPYCMD% %TMP_DIR%\library\server\wsf %TMP_CONTRIB_DIR%\library\web\framework\ewf\wsf - echo Install library: ewf/wsf_extension - %COPYCMD% %TMP_DIR%\library\server\wsf_extension %TMP_CONTRIB_DIR%\library\web\framework\ewf\wsf_extension -+echo Install library: ewf/wsf_proxy -+%COPYCMD% %TMP_DIR%\library\server\wsf_proxy %TMP_CONTRIB_DIR%\library\web\framework\ewf\wsf_proxy - echo Install library: ewf/wsf_html - %COPYCMD% %TMP_DIR%\library\server\wsf_html %TMP_CONTRIB_DIR%\library\web\framework\ewf\wsf_html - echo Install library: ewf/encoder diff --git a/examples/_update_needed/filter/filter.rc b/examples/_update_needed/filter/filter.rc deleted file mode 100644 index b0ec159c..00000000 --- a/examples/_update_needed/filter/filter.rc +++ /dev/null @@ -1,6 +0,0 @@ -#include - -STRINGTABLE -BEGIN - 1 "This Program was made using EiffelStudio using Visual Studio C++" -END diff --git a/examples/form/form.rc b/examples/form/form.rc deleted file mode 100644 index b0ec159c..00000000 --- a/examples/form/form.rc +++ /dev/null @@ -1,6 +0,0 @@ -#include - -STRINGTABLE -BEGIN - 1 "This Program was made using EiffelStudio using Visual Studio C++" -END diff --git a/examples/rest/licence_manager/ewf.ini b/examples/rest/licence_manager/ewf.ini deleted file mode 100644 index 5df94320..00000000 --- a/examples/rest/licence_manager/ewf.ini +++ /dev/null @@ -1,4 +0,0 @@ -# For Standalone connector, use port 9090 -port=9090 - -#verbose=true diff --git a/examples/rest/restbucks_CRUD/client/client.exe b/examples/rest/restbucks_CRUD/client/client.exe deleted file mode 100644 index 26e820ac9137556a757e4a0623524f3cfd2206af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1922560 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%0DO>Ovk$qUhF5}^?wXylnz{% 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

uRuH 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%0AVE@;R|aKmxDsdt-qZh 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 ryvKhw&Vo@BSDQq{X*W2pa!A`Z0a$J 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

A! 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Έa@xJ*Q3ny+77e@B%6-t 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