Compare commits
31 Commits
es17.05
...
es_rev1009
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edec837c4e | ||
|
|
f1642a444a | ||
|
|
48af63af83 | ||
|
|
2f98d7031f | ||
|
|
70f00651c7 | ||
|
|
199f84c7ef | ||
|
|
9b97627c76 | ||
|
|
72c87cd74d | ||
|
|
2ed4d03168 | ||
|
|
18ed92a61d | ||
|
|
0a6a4281e7 | ||
|
|
38cf5d7a6f | ||
|
|
96648a16dc | ||
|
|
6f35ad7b16 | ||
|
|
85c8a46c89 | ||
|
|
498e4a6ec2 | ||
|
|
ab507d543a | ||
|
|
20a90db2e3 | ||
|
|
6ed91699b8 | ||
|
|
bb334aef80 | ||
|
|
c2764e25ff | ||
|
|
6425482070 | ||
|
|
818c3fb460 | ||
|
|
dac50b490d | ||
|
|
16d5076fe5 | ||
|
|
2748e1d9ee | ||
|
|
27ee20f99b | ||
|
|
9a3164df70 | ||
|
|
02383810b4 | ||
|
|
dbf5e76047 | ||
|
|
5c31905427 |
19
.travis.yml
19
.travis.yml
@@ -0,0 +1,19 @@
|
||||
language: eiffel
|
||||
before_script:
|
||||
- export current_dir=$PWD ; echo current_dir=$current_dir ; cd ..
|
||||
- export ISE_VERSION=17.05; export ISE_BUILD=100416
|
||||
- curl -sSL http://downloads.sourceforge.net/eiffelstudio/Eiffel_${ISE_VERSION}_gpl_${ISE_BUILD}-linux-x86-64.tar.bz2 | tar -x --bzip2
|
||||
- export ISE_EIFFEL=$PWD/Eiffel_${ISE_VERSION} ; export ISE_PLATFORM=linux-x86-64
|
||||
- export PATH=$PATH:$ISE_EIFFEL/studio/spec/$ISE_PLATFORM/bin:$PATH:$ISE_EIFFEL/tools/spec/$ISE_PLATFORM/bin
|
||||
- echo `ec -version`
|
||||
- cd $current_dir
|
||||
- echo Check projects compilation status...
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- v1
|
||||
|
||||
script: compile_all -ecb -melt -list_failures -log_verbose -clean -options dotnet=false
|
||||
group: stable
|
||||
os: linux
|
||||
|
||||
@@ -7,14 +7,21 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- jwt: new JSON Web Token (JWT) library (supports for claim exp, iat, nbf, iss, aud).
|
||||
- `jwt`: new JSON Web Token (JWT) library (supports for claim exp, iat, nbf, iss, aud).
|
||||
- `http_client`: added support for ciphers setting in the libcurl implementation only.
|
||||
- `http_client`: added convenient `get` and `custom` functions on HTTP_CLIENT directly.
|
||||
|
||||
### Changed
|
||||
- adopted ecf version 1-16-0 and use a single .ecf file (the -safe.ecf are now redirection to normal .ecf)
|
||||
### Deprecated
|
||||
- removed support for Eiffel version before 17.05 .
|
||||
- SSL 2 or 3 is obsolete and will raise an exception if used.
|
||||
### Removed
|
||||
### Fixed
|
||||
- Removed a few obsolete calls.
|
||||
- `http_client`: Added support for multiple file in form data. Made clear what is the meaning of `upload_filename`, `upload_data` and `form_data`.
|
||||
- `authentication`: HTTP_AUTHORIZATION acceps now READABLE_STRING_GENERAL for username and password argument.
|
||||
- `http_client`: fixed curl implementation by setting `Content-Type` to `x-www-form-urlencoded` (if not set) when POST send data as `x-www-form-urlencoded`.
|
||||
### Security
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Eiffel Web Framework
|
||||
|
||||
[](https://travis-ci.org/EiffelWebFramework/EWF/)
|
||||
|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package nino
|
||||
|
||||
project
|
||||
nino = "nino-safe.ecf"
|
||||
nino = "nino.ecf"
|
||||
|
||||
note
|
||||
|
||||
@@ -10,6 +10,9 @@ It provides simple routine to perform http requests, and get response.
|
||||
- Eiffel Net library
|
||||
- and optionally Eiffel NetSSL library to support `https://...`
|
||||
|
||||
* Note: set ciphers setting is supported only with libcurl implementation for now, net implementation
|
||||
set all the ciphers as part of the OpenSSL initialization.
|
||||
|
||||
This means on Windows, do not forget to copy the libcurl.dll (and related) either in the same directory of the executable, or ensure the .dll are in the PATH environment.
|
||||
|
||||
It is possible to exclude the libcurl implementation xor the Eiffel Net implementation:
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
<exclude>/\.svn$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="curl" location="$ISE_LIBRARY\library\cURL\cURL.ecf">
|
||||
<condition>
|
||||
@@ -32,8 +30,8 @@
|
||||
</library>
|
||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf"/>
|
||||
<cluster name="src" location=".\src\">
|
||||
<cluster name="implementation" location="$|implementation" recursive="true" hidden="true"/>
|
||||
<cluster name="parameters" location="$|parameters" recursive="true"/>
|
||||
<cluster name="implementation" location="$|implementation\" recursive="true" hidden="true"/>
|
||||
<cluster name="parameters" location="$|parameters\" recursive="true"/>
|
||||
<cluster name="spec_null" location="$|spec\null\" recursive="true"/>
|
||||
<cluster name="spec_net" location="$|spec\net\">
|
||||
<condition>
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
<exclude>/\.svn$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="curl" location="$ISE_LIBRARY\library\cURL\cURL.ecf"/>
|
||||
<library name="encoder" location="..\..\text\encoder\encoder.ecf"/>
|
||||
@@ -16,8 +14,8 @@
|
||||
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf"/>
|
||||
<cluster name="src" location=".\src\">
|
||||
<cluster name="implementation" location="$|implementation" recursive="true" hidden="true"/>
|
||||
<cluster name="parameters" location="$|parameters" recursive="true"/>
|
||||
<cluster name="implementation" location="$|implementation\" recursive="true" hidden="true"/>
|
||||
<cluster name="parameters" location="$|parameters\" recursive="true"/>
|
||||
<cluster name="spec_libcurl" location="$|spec\libcurl\" recursive="true"/>
|
||||
<cluster name="default_libcurl" location="$|default\libcurl\"/>
|
||||
</cluster>
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
<exclude>/\.svn$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="encoder" location="..\..\text\encoder\encoder.ecf"/>
|
||||
<library name="http" location="..\protocol\http\http.ecf"/>
|
||||
@@ -25,8 +23,8 @@
|
||||
</library>
|
||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf"/>
|
||||
<cluster name="src" location=".\src\">
|
||||
<cluster name="implementation" location="$|implementation" recursive="true" hidden="true"/>
|
||||
<cluster name="parameters" location="$|parameters" recursive="true"/>
|
||||
<cluster name="implementation" location="$|implementation\" recursive="true" hidden="true"/>
|
||||
<cluster name="parameters" location="$|parameters\" recursive="true"/>
|
||||
<cluster name="spec_net" location="$|spec\net\">
|
||||
<cluster name="net_implementation" location="$|implementation\" hidden="true"/>
|
||||
</cluster>
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
package http_client
|
||||
|
||||
project
|
||||
http_client = "http_client-safe.ecf"
|
||||
http_client = "http_client.ecf"
|
||||
libcurl_http_client = "libcurl_http_client-safe.ecf"
|
||||
libcurl_http_client = "libcurl_http_client.ecf"
|
||||
net_http_client = "net_http_client-safe.ecf"
|
||||
net_http_client = "net_http_client.ecf"
|
||||
|
||||
note
|
||||
title: HTTP client
|
||||
description: "[
|
||||
Provides simple routines to perform http requests, and get associated response.
|
||||
It has two implementations:
|
||||
- using Eiffel cURL (i.e libcurl)
|
||||
- using EiffelNET (and the EiffelNET SSL extension)
|
||||
]"
|
||||
collection:EWF
|
||||
description: "[
|
||||
Provides simple routines to perform http requests, and get associated response.
|
||||
It has two implementations:
|
||||
- using Eiffel cURL (i.e libcurl)
|
||||
- using EiffelNET (and the EiffelNET SSL extension)
|
||||
]"
|
||||
|
||||
collection: EWF
|
||||
tags: http,client,network,request,web,curl,EWF
|
||||
copyright: 1984-2016 Eiffel Software and others
|
||||
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||
|
||||
@@ -16,8 +16,19 @@ feature -- Access
|
||||
deferred
|
||||
end
|
||||
|
||||
get (a_url: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
do
|
||||
Result := new_session (a_url).get ("", ctx)
|
||||
end
|
||||
|
||||
custom (a_method: READABLE_STRING_8; a_url: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||
-- Response for `a_method' request based on `a_url' and optional `ctx'.
|
||||
do
|
||||
Result := new_session (a_url).custom (a_method, "", ctx)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -30,8 +30,19 @@ feature {NONE} -- Initialization
|
||||
-- Initialize Current with `a_url' and `ctx'.
|
||||
-- This can be used to reset/reinitialize Current with new url
|
||||
-- in the case of redirection.
|
||||
local
|
||||
i: INTEGER
|
||||
do
|
||||
url := a_url
|
||||
i := a_url.substring_index ("://", 1)
|
||||
if i > 0 then
|
||||
check
|
||||
a_url.substring (1, i).same_string ("http")
|
||||
or a_url.substring (1, i).same_string ("https")
|
||||
end
|
||||
url := a_url
|
||||
else
|
||||
url := session.url (a_url, Void)
|
||||
end
|
||||
headers := session.headers.twin
|
||||
if ctx /= Void then
|
||||
context := ctx
|
||||
|
||||
@@ -272,6 +272,14 @@ feature -- Authentication
|
||||
-- Associated optional credentials value.
|
||||
-- Computed as `username':`password'.
|
||||
|
||||
ciphers_setting: detachable READABLE_STRING_8
|
||||
-- SSL cipher preference lists
|
||||
-- examples: DEFAULT, ALL, TLSv1
|
||||
-- check https://www.openssl.org/docs/man1.1.0/apps/ciphers.html
|
||||
-- Warning: At the moment only used for LIB_CURL_HTTP_CLIENT
|
||||
-- Net implementation set all the ciphers using the OpenSSL at
|
||||
-- initialization time.
|
||||
|
||||
feature -- Status setting
|
||||
|
||||
set_is_debug (b: BOOLEAN)
|
||||
@@ -401,6 +409,14 @@ feature -- Element change
|
||||
chunk_size := a_size
|
||||
end
|
||||
|
||||
set_ciphers_setting (a_ciphers_setting: READABLE_STRING_8)
|
||||
-- Set 'ciphers_setting' with 'a_ciphers_setting'.
|
||||
do
|
||||
create {STRING_8} ciphers_setting.make_from_string (a_ciphers_setting)
|
||||
ensure
|
||||
ciphers_setting_set: attached ciphers_setting as c_setting and then c_setting.same_string (a_ciphers_setting)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
@@ -206,7 +206,10 @@ feature -- Execution
|
||||
l_use_curl_form := True
|
||||
end
|
||||
else
|
||||
l_headers.force ("application/x-www-form-urlencoded", "Content-Type")
|
||||
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
||||
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_postfields, l_upload_data)
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_postfieldsize, l_upload_data.count)
|
||||
end
|
||||
if l_use_curl_form then
|
||||
create l_form.make
|
||||
@@ -372,6 +375,11 @@ feature -- Execution
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_ssl_verifypeer, 0)
|
||||
end
|
||||
|
||||
--| Cipher List
|
||||
if attached session.ciphers_setting as c_list then
|
||||
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_ssl_cipher_list, c_list )
|
||||
end
|
||||
|
||||
--| Request method
|
||||
if request_method.is_case_insensitive_equal ("GET") then
|
||||
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpget, 1)
|
||||
|
||||
@@ -113,6 +113,7 @@ feature -- Access
|
||||
-- Get URL data
|
||||
l_is_https := url.starts_with_general ("https://")
|
||||
create l_uri.make_from_string (url)
|
||||
check valid_url: l_uri.is_valid end
|
||||
l_port := l_uri.port
|
||||
if l_port = 0 then
|
||||
if l_is_https then
|
||||
|
||||
@@ -7,117 +7,32 @@
|
||||
<exclude>/\.svn$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true">
|
||||
</option>
|
||||
<external_include location="$ECF_CONFIG_PATH/spec/include">
|
||||
<condition>
|
||||
<version type="compiler" min="16.9.9.9124"/>
|
||||
</condition>
|
||||
</external_include>
|
||||
<external_include location="$ECF_CONFIG_PATH/spec/include_until_16_05">
|
||||
<condition>
|
||||
<version type="compiler" max="16.9.9.9124"/>
|
||||
</condition>
|
||||
</external_include>
|
||||
<external_include location="$(ISE_LIBRARY)/unstable/library/network/socket/netssl/spec/include">
|
||||
<condition>
|
||||
<platform excluded_value="windows"/>
|
||||
<version type="compiler" max="16.9.9.9124"/>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</external_include>
|
||||
<external_include location="$(ISE_LIBRARY)\unstable\library\network\socket\netssl\spec\include">
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
<version type="compiler" max="16.9.9.9124"/>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</external_include>
|
||||
<external_cflag value="-D_WINSOCKAPI_">
|
||||
<condition>
|
||||
<platform value="windows"/>
|
||||
<version type="compiler" max="16.9.9.9124"/>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</external_cflag>
|
||||
<external_include location="$ECF_CONFIG_PATH/spec/include"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
||||
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl.ecf">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</library>
|
||||
<library name="openssl" location="$ISE_LIBRARY\unstable\library\network\openssl\openssl.ecf">
|
||||
<condition>
|
||||
<custom name="net_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
<version type="compiler" min="17.10.0.0"/>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</library>
|
||||
<cluster name="network" location=".\src\">
|
||||
<file_rule>
|
||||
<exclude>/http_stream_socket_ext.e$</exclude>
|
||||
<condition>
|
||||
<version type="compiler" max="17.02"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
<cluster name="disabled_ssl_network" location="$|no_ssl\" recursive="true">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" excluded_value="true"/>
|
||||
<custom name="net_ssl_enabled" excluded_value="true"/>
|
||||
<custom name="httpd_ssl_enabled" excluded_value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="ssl_network" location="$|ssl\" recursive="true">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="net_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<file_rule>
|
||||
<exclude>/http_stream_secure_socket_ext.e$</exclude>
|
||||
<condition>
|
||||
<version type="compiler" max="16.9.9.9124"/>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<version type="compiler" max="16.9.9.9124"/>
|
||||
<custom name="net_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<version type="compiler" max="16.9.9.9124"/>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</cluster>
|
||||
<cluster name="network_until_16_05" location=".\src\until_16_05\">
|
||||
<condition>
|
||||
<version type="compiler" max="16.9.9.9124"/>
|
||||
</condition>
|
||||
<cluster name="ssl_network_until_16_05" location="$|ssl\" recursive="true">
|
||||
<condition>
|
||||
<version type="compiler" max="16.9.9.9124"/>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<version type="compiler" max="16.9.9.9124"/>
|
||||
<custom name="net_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<version type="compiler" max="16.9.9.9124"/>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
</cluster>
|
||||
<cluster name="network_until_17_01" location=".\src\until_17_01\">
|
||||
<condition>
|
||||
<version type="compiler" min="16.9.9.9124" max="17.02"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
</target>
|
||||
<target name="http_network_ssl" extends="http_network">
|
||||
<variable name="ssl_enabled" value="true"/>
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
indexing
|
||||
description: "Functions used by the EiffelWeb http networking classes. "
|
||||
copyright: "Copyright (c) 2011-2016, Jocelyn Fiat, 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
|
||||
]"
|
||||
*/
|
||||
|
||||
#ifndef _ew_network_h_
|
||||
#define _ew_network_h_
|
||||
|
||||
#include "eif_config.h"
|
||||
|
||||
#ifdef EIF_WINDOWS
|
||||
# ifndef _WINSOCKAPI_
|
||||
# define FD_SETSIZE 256
|
||||
# include <winsock2.h>
|
||||
# include <Ws2tcpip.h>
|
||||
# include <stdio.h>
|
||||
# endif
|
||||
#else /* unix-specific */
|
||||
# include <sys/socket.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* extern declarations ... */
|
||||
#ifdef EIF_WINDOWS
|
||||
extern int setsockopt(int, int, int, char*, int);
|
||||
extern int recv(int, char *, int, int);
|
||||
extern int send(int, char *, int, int);
|
||||
#else
|
||||
extern int setsockopt(int, int, int, const void*, socklen_t);
|
||||
extern ssize_t recv(int, void *, size_t, int);
|
||||
extern ssize_t send(int, const void *, size_t, int);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -9,8 +9,6 @@ class
|
||||
inherit
|
||||
NETWORK_STREAM_SOCKET
|
||||
|
||||
HTTP_STREAM_SOCKET_EXT
|
||||
|
||||
create
|
||||
make, make_empty,
|
||||
make_client_by_port, make_client_by_address_and_port,
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
Extension to HTTPD_STREAM_SOCKET to support backward compatibility.
|
||||
|
||||
TO BE REMOVED IN THE FUTURE, When there is no need to support older compilers.
|
||||
]"
|
||||
|
||||
deferred class
|
||||
HTTP_STREAM_SOCKET_EXT
|
||||
|
||||
note
|
||||
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
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
|
||||
@@ -55,12 +55,19 @@ feature -- Secure connection Helpers
|
||||
end
|
||||
|
||||
set_secure_protocol_to_ssl_2_or_3
|
||||
-- Set `ssl_protocol' with `Ssl_23'.
|
||||
do
|
||||
set_secure_protocol ({SSL_PROTOCOL}.Ssl_23)
|
||||
end
|
||||
-- Set `ssl_protocol' with `Ssl_23'.
|
||||
-- Protocol not supported anymore.
|
||||
obsolete
|
||||
"Use set_secure_protocol_to_tls_1_2 [2017-06-23]."
|
||||
local
|
||||
err: DEVELOPER_EXCEPTION
|
||||
do
|
||||
create err
|
||||
err.set_description ("SSL_2 or SSL_3 are not supported anymore, upgrate to TLS set_secure_protocol_to_tls_1_2")
|
||||
err.raise
|
||||
end
|
||||
|
||||
set_secure_protocol_to_tls_1_0
|
||||
set_secure_protocol_to_tls_1_0
|
||||
-- Set `ssl_protocol' with `Tls_1_0'.
|
||||
do
|
||||
set_secure_protocol ({SSL_PROTOCOL}.Tls_1_0)
|
||||
@@ -176,7 +183,14 @@ feature -- Output
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat and others"
|
||||
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
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
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
Until 16.05, the EiffelNet socket interface DOES NOT have
|
||||
- make_server_by_address_and_port
|
||||
- recv_timeout
|
||||
- send_timeout.
|
||||
|
||||
TO BE REMOVED IN THE FUTURE, WHEN 16.05 IS OLD.
|
||||
]"
|
||||
|
||||
deferred class
|
||||
HTTP_STREAM_SOCKET_EXT
|
||||
|
||||
inherit
|
||||
PLATFORM
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make
|
||||
deferred
|
||||
end
|
||||
|
||||
make_server_by_address_and_port (a_address: INET_ADDRESS; a_port: INTEGER)
|
||||
-- Create server socket on `a_address' and `a_port'.
|
||||
require
|
||||
valid_port: a_port >= 0
|
||||
do
|
||||
make
|
||||
set_address (create {like address_type}.make_from_address_and_port (a_address, a_port))
|
||||
bind
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
bind
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
set_address (addr: detachable like address_type)
|
||||
deferred
|
||||
end
|
||||
|
||||
address_type: NETWORK_SOCKET_ADDRESS
|
||||
deferred
|
||||
end
|
||||
|
||||
descriptor: INTEGER
|
||||
-- Socket descriptor of current socket
|
||||
deferred
|
||||
end
|
||||
|
||||
socket_buffer: MANAGED_POINTER
|
||||
deferred
|
||||
end
|
||||
|
||||
read_socket_buffer: MANAGED_POINTER
|
||||
do
|
||||
Result := socket_buffer
|
||||
end
|
||||
|
||||
put_socket_buffer: MANAGED_POINTER
|
||||
do
|
||||
Result := socket_buffer
|
||||
end
|
||||
|
||||
feature -- Socket Recv and Send timeout.
|
||||
|
||||
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
|
||||
|
||||
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 use %"ew_network.h%""
|
||||
alias
|
||||
"[
|
||||
#ifdef SO_RCVTIMEO
|
||||
int flag = SO_RCVTIMEO;
|
||||
#else
|
||||
int flag = 0x1006;
|
||||
#endif
|
||||
|
||||
#ifdef EIF_WINDOWS
|
||||
int arg = (int) 1000 * $a_timeout_seconds; /* Timeout in milliseconds */
|
||||
setsockopt((int) $a_fd, (int) $a_level, flag, (char *) &arg, sizeof(arg));
|
||||
#else
|
||||
struct timeval tv;
|
||||
tv.tv_sec = $a_timeout_seconds; /* Timeout in seconds */
|
||||
tv.tv_usec = 0;
|
||||
setsockopt((int) $a_fd, (int) $a_level, flag, (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 use %"ew_network.h%""
|
||||
alias
|
||||
"[
|
||||
#ifdef SO_RCVTIMEO
|
||||
int flag = SO_SNDTIMEO;
|
||||
#else
|
||||
int flag = 0x1005;
|
||||
#endif
|
||||
#ifdef EIF_WINDOWS
|
||||
int arg = (int) 1000 * $a_timeout_seconds; /* Timeout in milliseconds */
|
||||
setsockopt((int) $a_fd, (int) $a_level, flag, (char *) &arg, sizeof(arg));
|
||||
#else
|
||||
struct timeval tv;
|
||||
tv.tv_sec = $a_timeout_seconds; /* Timeout in seconds */
|
||||
tv.tv_usec = 0;
|
||||
setsockopt((int) $a_fd, (int) $a_level, flag, (struct timeval *)&tv, sizeof(struct timeval));
|
||||
#endif
|
||||
]"
|
||||
end
|
||||
|
||||
feature {NONE} -- No-Exception network operation
|
||||
|
||||
c_recv_noexception (a_fd: INTEGER; buf: POINTER; len: INTEGER; flags: INTEGER): INTEGER
|
||||
-- External routine to read a `len' number of characters
|
||||
-- into buffer `buf' from socket `a_fd' with options `flags'.
|
||||
external
|
||||
"C inline use %"ew_network.h%""
|
||||
alias
|
||||
"[
|
||||
recv((int) $a_fd, (char *) $buf, (int) $len, (int) $flags)
|
||||
]"
|
||||
end
|
||||
|
||||
c_read_stream_noexception (a_fd: INTEGER; len: INTEGER; buf: POINTER): INTEGER
|
||||
-- External routine to read a `len' number of characters
|
||||
-- into buffer `buf' from socket `a_fd'.
|
||||
do
|
||||
Result := c_recv_noexception (a_fd, buf, len, 0)
|
||||
end
|
||||
|
||||
c_put_stream_noexception (a_fd: INTEGER; buf: POINTER; len: INTEGER): INTEGER
|
||||
-- External routine to write stream pointed by `s' of
|
||||
-- length `length' to socket `fd'.
|
||||
-- Note: does not raise exception on error, but return error value as Result.
|
||||
external
|
||||
"C inline use %"ew_network.h%""
|
||||
alias
|
||||
"[
|
||||
send((int) $a_fd, (char *) $buf, (int) $len, (int) 0)
|
||||
]"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,41 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
Extension to HTTP_STREAM_SOCKET to support backward compatibility.
|
||||
|
||||
TO BE REMOVED IN THE FUTURE, WHEN 16.05 IS OLD.
|
||||
]"
|
||||
|
||||
deferred class
|
||||
HTTP_STREAM_SECURE_SOCKET_EXT
|
||||
|
||||
feature {NONE} -- SSL bridge
|
||||
|
||||
ssl_write (a_ssl: SSL; a_pointer: POINTER; a_byte_count: INTEGER): INTEGER
|
||||
do
|
||||
-- In delivery until 16.05
|
||||
-- SSL.write does not return any value!
|
||||
-- So let's use `c_ssl_write' from Current class
|
||||
-- instead of:
|
||||
-- a_ssl.write (a_pointer, a_byte_count)
|
||||
|
||||
Result := c_ssl_write (a_ssl.ptr, a_pointer, a_byte_count)
|
||||
if a_ssl.was_error then
|
||||
-- Until 16.05, there is no error check for `SSL.write'
|
||||
-- so nothing can be done here.
|
||||
|
||||
if Result >= 0 then
|
||||
Result := -1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
c_ssl_write (an_ssl_ptr: POINTER; buffer: POINTER; nb_bytes: INTEGER_32): INTEGER_32
|
||||
-- External call to SSL_write
|
||||
-- (export status {NONE})
|
||||
external
|
||||
"C use %"eif_openssl.h%""
|
||||
alias
|
||||
"SSL_write"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,29 +0,0 @@
|
||||
note
|
||||
description: "[
|
||||
Extension to HTTPD_STREAM_SOCKET to support backward compatibility.
|
||||
|
||||
TO BE REMOVED IN THE FUTURE, WHEN 17.01 IS OLD.
|
||||
]"
|
||||
|
||||
deferred class
|
||||
HTTP_STREAM_SOCKET_EXT
|
||||
|
||||
feature -- Access
|
||||
|
||||
socket_buffer: MANAGED_POINTER
|
||||
deferred
|
||||
end
|
||||
|
||||
read_socket_buffer: MANAGED_POINTER
|
||||
do
|
||||
Result := socket_buffer
|
||||
end
|
||||
|
||||
put_socket_buffer: MANAGED_POINTER
|
||||
do
|
||||
Result := socket_buffer
|
||||
end
|
||||
|
||||
feature {NONE} -- No-Exception network operation
|
||||
|
||||
end
|
||||
@@ -1,14 +1,14 @@
|
||||
package content_negotiation
|
||||
|
||||
project
|
||||
conneg = "conneg-safe.ecf"
|
||||
conneg = "conneg.ecf"
|
||||
|
||||
note
|
||||
title: CONneg Content Negotiation
|
||||
description: "[
|
||||
CONneg is a library that provides utilities to select the best repesentation of a resource for a client where there are multiple representations available.
|
||||
]"
|
||||
CONneg is a library that provides utilities to select the best repesentation of a resource for a client where there are multiple representations available.
|
||||
]"
|
||||
|
||||
collection: EWF
|
||||
tags: content,accept,conneg,negotiation,EWF,web,request
|
||||
copyright: 2011-2016, Javier Velilla, Jocelyn Fiat, Eiffel Software and others
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
package http
|
||||
|
||||
project
|
||||
http = "http-safe.ecf"
|
||||
http = "http.ecf"
|
||||
|
||||
note
|
||||
title: HTTP protocol
|
||||
description: "[
|
||||
Collection of interfaces related to HTTP protocol:
|
||||
- header
|
||||
- status codes, request methods
|
||||
- content type, media type, mime type.
|
||||
- cookie
|
||||
- date used in web protocol
|
||||
- file extension mime mapping
|
||||
]"
|
||||
Collection of interfaces related to HTTP protocol:
|
||||
- header
|
||||
- status codes, request methods
|
||||
- content type, media type, mime type.
|
||||
- cookie
|
||||
- date used in web protocol
|
||||
- file extension mime mapping
|
||||
]"
|
||||
|
||||
collection: EWF
|
||||
tags: http,web,header,status,method,type,mime,cookie
|
||||
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
package notification_email
|
||||
|
||||
project
|
||||
notification_email = "notification_email-safe.ecf"
|
||||
notification_email = "notification_email.ecf"
|
||||
|
||||
note
|
||||
title: Notification Email
|
||||
description: "[
|
||||
Abstract interface to send message via various mailers:
|
||||
- smtp
|
||||
- sendmail
|
||||
- external script
|
||||
- store on local file
|
||||
- ...
|
||||
]"
|
||||
Abstract interface to send message via various mailers:
|
||||
- smtp
|
||||
- sendmail
|
||||
- external script
|
||||
- store on local file
|
||||
- ...
|
||||
]"
|
||||
|
||||
collection: EWF
|
||||
tags: message,smtp,sendmail,mailer
|
||||
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: 2011-2016, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others
|
||||
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||
link[source]: "github" https://github.com/EiffelWebFramework/EWF/tree/master/library/runtime/process/notification_email
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
<root all_classes="true"/>
|
||||
<option warning="true">
|
||||
</option>
|
||||
<capability>
|
||||
<concurrency support="scoop" use="scoop"/>
|
||||
<void_safety support="all" use="all"/>
|
||||
</capability>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto.ecf"/>
|
||||
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder.ecf"/>
|
||||
|
||||
@@ -6,7 +6,7 @@ project
|
||||
note
|
||||
title: JSON Web Token
|
||||
description: JSON Web Token
|
||||
tags:jwt,web,jws,jwe,token,jose
|
||||
tags: jwt,web,jws,jwe,token,jose
|
||||
copyright: 2011-2017, Jocelyn Fiat, Eiffel Software and others
|
||||
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||
|
||||
36
library/security/jwt/src/errors/jwt_mismatched_alg_error.e
Normal file
36
library/security/jwt/src/errors/jwt_mismatched_alg_error.e
Normal file
@@ -0,0 +1,36 @@
|
||||
note
|
||||
description: "Summary description for {JWT_MISMATCHED_ALG_ERROR}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
JWT_MISMATCHED_ALG_ERROR
|
||||
|
||||
inherit
|
||||
JWT_ERROR
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_alg, a_header_alg: READABLE_STRING_8)
|
||||
do
|
||||
alg := a_alg
|
||||
header_alg := a_header_alg
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
alg: READABLE_STRING_8
|
||||
|
||||
header_alg: READABLE_STRING_8
|
||||
|
||||
id: STRING = "ALG_MISMATCH"
|
||||
|
||||
message: READABLE_STRING_8
|
||||
do
|
||||
Result := "Header alg [" + header_alg + "] does not match given alg [" + alg + "]!"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -59,6 +59,8 @@ feature -- Status report
|
||||
do
|
||||
if attached claimset.issuer as iss then
|
||||
Result := a_issuer = Void or else a_issuer.same_string (iss)
|
||||
else
|
||||
Result := a_issuer = Void
|
||||
end
|
||||
end
|
||||
|
||||
@@ -66,6 +68,8 @@ feature -- Status report
|
||||
do
|
||||
if attached claimset.audience as aud then
|
||||
Result := a_audience = Void or else a_audience.same_string (aud)
|
||||
else
|
||||
Result := a_audience = Void
|
||||
end
|
||||
end
|
||||
|
||||
@@ -118,6 +122,11 @@ feature {JWT_UTILITIES} -- Error reporting
|
||||
l_errors.extend (err)
|
||||
end
|
||||
|
||||
report_mismatched_alg_error (alg, a_header_alg: READABLE_STRING_8)
|
||||
do
|
||||
report_error (create {JWT_MISMATCHED_ALG_ERROR}.make (alg, a_header_alg))
|
||||
end
|
||||
|
||||
report_unsupported_alg_error (alg: READABLE_STRING_8)
|
||||
do
|
||||
report_error (create {JWT_UNSUPPORTED_ALG_ERROR}.make (alg))
|
||||
|
||||
@@ -266,11 +266,10 @@ feature {NONE} -- Implementation
|
||||
|
||||
base64_hmacsha256 (s: READABLE_STRING_8; a_secret: READABLE_STRING_8): STRING_8
|
||||
local
|
||||
hs256: HMAC_SHA256
|
||||
ut: JWT_UTILITIES
|
||||
do
|
||||
create hs256.make_ascii_key (a_secret)
|
||||
hs256.update_from_string (s)
|
||||
Result := hs256.base64_digest --lowercase_hexadecimal_string_digest
|
||||
create ut
|
||||
Result := ut.base64_hmacsha256 (s, a_secret)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
note
|
||||
description: "Summary description for {JWT_LOADER}."
|
||||
author: ""
|
||||
description: "Loader and verifier to JWT token."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
EIS: "name=Known Critical vulnerabilities in JWT libs", "protocol=URI", "src=https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/"
|
||||
|
||||
class
|
||||
JWT_LOADER
|
||||
@@ -12,9 +12,13 @@ inherit
|
||||
|
||||
feature -- Access
|
||||
|
||||
token (a_token_input: READABLE_STRING_8; a_secret: READABLE_STRING_8; ctx: detachable JWT_CONTEXT): detachable JWT
|
||||
-- Decoded token from `a_token_input` given the secret `a_secret`, and optional context `ctx`
|
||||
token (a_token_input: READABLE_STRING_8; a_alg: detachable READABLE_STRING_8; a_verification_key: READABLE_STRING_8; ctx: detachable JWT_CONTEXT): detachable JWT
|
||||
-- Decoded token from `a_token_input` given the verification key `a_verification_key` and optional (but recommended) signature algorithm `a_alg`, and optional context `ctx`
|
||||
-- used to specify eventual issuer and various parameters.
|
||||
-- WARNING: passing Void for `a_alg` is not safe, as the server should know which alg he used for tokens,
|
||||
-- leaving the possibility to use the header alg is dangerous as client may use "none" and then bypass verification!
|
||||
require
|
||||
a_valid_alg: a_alg /= Void implies is_supporting_signature_algorithm (a_alg)
|
||||
local
|
||||
jws: JWS
|
||||
i,j,n: INTEGER
|
||||
@@ -29,20 +33,27 @@ feature -- Access
|
||||
l_enc_payload := a_token_input.substring (i + 1, j - 1)
|
||||
l_signature := a_token_input.substring (j + 1, n)
|
||||
create jws.make_with_json_payload (base64url_decode (l_enc_payload))
|
||||
|
||||
alg := signature_algorithm_from_encoded_header (l_enc_header)
|
||||
jws.set_algorithm (alg)
|
||||
if alg = Void then
|
||||
-- Use default
|
||||
alg := alg_hs256
|
||||
if a_alg /= Void then
|
||||
if alg /= Void and then not alg.is_case_insensitive_equal_general (a_alg) then
|
||||
jws.report_mismatched_alg_error (a_alg, alg)
|
||||
else
|
||||
alg := a_alg
|
||||
end
|
||||
else
|
||||
if alg = Void then
|
||||
-- Use default
|
||||
alg := alg_hs256
|
||||
end
|
||||
end
|
||||
jws.set_algorithm (alg)
|
||||
check alg_set: alg /= Void end
|
||||
if ctx = Void or else not ctx.validation_ignored then
|
||||
if not is_supporting_signature_algorithm (alg) then
|
||||
jws.report_unsupported_alg_error (alg)
|
||||
alg := alg_hs256
|
||||
end
|
||||
if not l_signature.same_string (signature (l_enc_header, l_enc_payload, a_secret, alg)) then
|
||||
if not l_signature.same_string (signature (l_enc_header, l_enc_payload, a_verification_key, alg)) then
|
||||
jws.report_unverified_token_error
|
||||
end
|
||||
if
|
||||
|
||||
@@ -61,7 +61,33 @@ feature -- Encoding
|
||||
do
|
||||
create hs256.make_ascii_key (a_secret)
|
||||
hs256.update_from_string (s)
|
||||
Result := hs256.base64_digest --lowercase_hexadecimal_string_digest
|
||||
-- if Version >= EiffelStudio 17.11 then
|
||||
-- Result := hs256.base64_digest --lowercase_hexadecimal_string_digest
|
||||
-- else
|
||||
Result := base64_bytes_encoded_string (hs256.digest)
|
||||
-- end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
base64_bytes_encoded_string (a_bytes: SPECIAL [NATURAL_8]): STRING_8
|
||||
-- Base64 string from `a_bytes`.
|
||||
--| Note: to be removed when 17.11 is not latest release anymore.
|
||||
local
|
||||
s: STRING
|
||||
i,n: INTEGER
|
||||
do
|
||||
from
|
||||
i := 1
|
||||
n := a_bytes.count
|
||||
create s.make (n)
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
s.append_code (a_bytes[i - 1])
|
||||
i := i + 1
|
||||
end
|
||||
Result := (create {BASE64}).encoded_string (s)
|
||||
end
|
||||
|
||||
feature -- Decoding
|
||||
|
||||
@@ -54,7 +54,14 @@ feature -- Test
|
||||
|
||||
create jwt_loader
|
||||
|
||||
if attached jwt_loader.token (tok, "secret", Void) as l_tok then
|
||||
-- Use header alg!
|
||||
if attached jwt_loader.token (tok, Void, "secret", Void) as l_tok then
|
||||
assert ("no error", not l_tok.has_error)
|
||||
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||
end
|
||||
|
||||
-- Use given alg!
|
||||
if attached jwt_loader.token (tok, jwt.algorithm, "secret", Void) as l_tok then
|
||||
assert ("no error", not l_tok.has_error)
|
||||
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||
end
|
||||
@@ -96,21 +103,21 @@ feature -- Test
|
||||
create jwt_loader
|
||||
|
||||
-- Test with validation + exp
|
||||
if attached jwt_loader.token (tok, "secret", Void) as l_tok then
|
||||
if attached jwt_loader.token (tok, jwt.algorithm, "secret", Void) as l_tok then
|
||||
assert ("no error", not l_tok.has_error)
|
||||
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||
end
|
||||
|
||||
create ctx
|
||||
ctx.set_time (now)
|
||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
||||
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||
assert ("no error", not l_tok.has_error)
|
||||
end
|
||||
|
||||
dt := duplicated_time (now)
|
||||
dt.hour_add (5)
|
||||
ctx.set_time (dt)
|
||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
||||
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||
assert ("exp error", l_tok.has_error)
|
||||
end
|
||||
|
||||
@@ -122,7 +129,7 @@ feature -- Test
|
||||
tok := jwt.encoded_string ("secret")
|
||||
|
||||
ctx.set_time (now)
|
||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
||||
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||
assert ("has nbf error", l_tok.has_error)
|
||||
end
|
||||
|
||||
@@ -130,7 +137,7 @@ feature -- Test
|
||||
dt.second_add (15)
|
||||
ctx.set_time (dt)
|
||||
|
||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
||||
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||
assert ("has nbf error", l_tok.has_error)
|
||||
end
|
||||
|
||||
@@ -138,31 +145,51 @@ feature -- Test
|
||||
dt.minute_add (45)
|
||||
ctx.set_time (dt)
|
||||
|
||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
||||
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||
assert ("no error", not l_tok.has_error)
|
||||
end
|
||||
|
||||
-- Test Issuer
|
||||
ctx.set_issuer ("urn:foobar")
|
||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
||||
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||
assert ("has iss error", l_tok.has_error)
|
||||
end
|
||||
ctx.set_issuer ("urn:foo")
|
||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
||||
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||
assert ("no error", not l_tok.has_error)
|
||||
end
|
||||
|
||||
-- Test Audience
|
||||
ctx.set_audience ("urn:foobar")
|
||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
||||
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||
assert ("has aud error", l_tok.has_error)
|
||||
end
|
||||
ctx.set_audience ("urn:foo")
|
||||
if attached jwt_loader.token (tok, "secret", ctx) as l_tok then
|
||||
if attached jwt_loader.token (tok, jwt.algorithm, "secret", ctx) as l_tok then
|
||||
assert ("no error", not l_tok.has_error)
|
||||
end
|
||||
end
|
||||
|
||||
test_mismatched_alg_jwt
|
||||
local
|
||||
jwt: JWS
|
||||
payload: STRING
|
||||
tok: STRING
|
||||
do
|
||||
payload := "[
|
||||
{"iss":"joe","exp":1300819380,"http://example.com/is_root":true}
|
||||
]"
|
||||
|
||||
create jwt.make_with_json_payload (payload)
|
||||
jwt.set_algorithm ("none")
|
||||
tok := jwt.encoded_string ("secret")
|
||||
|
||||
if attached (create {JWT_LOADER}).token (tok, "HS256", "secret", Void) as l_tok then
|
||||
assert ("no error", not jwt.has_error)
|
||||
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||
end
|
||||
end
|
||||
|
||||
test_unsecured_jwt
|
||||
local
|
||||
jwt: JWS
|
||||
@@ -177,7 +204,11 @@ feature -- Test
|
||||
jwt.set_algorithm ("none")
|
||||
tok := jwt.encoded_string ("secret")
|
||||
|
||||
if attached (create {JWT_LOADER}).token (tok, "secret", Void) as l_tok then
|
||||
if attached (create {JWT_LOADER}).token (tok, "none", "secret", Void) as l_tok then
|
||||
assert ("no error", not jwt.has_error)
|
||||
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||
end
|
||||
if attached (create {JWT_LOADER}).token (tok, Void, "secret", Void) as l_tok then
|
||||
assert ("no error", not jwt.has_error)
|
||||
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||
end
|
||||
|
||||
@@ -2,11 +2,10 @@ package openid
|
||||
|
||||
project
|
||||
openid = "consumer/openid.ecf"
|
||||
openid = "consumer/openid-safe.ecf"
|
||||
|
||||
note
|
||||
title: Eiffel OpenID
|
||||
description: OpenID consumer library
|
||||
description: OpenID consumer library
|
||||
tags: openid,security,web,authentication,sso
|
||||
copyright: 2011-2016, Jocelyn Fiat, Eiffel Software and others
|
||||
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||
@@ -15,4 +14,3 @@ note
|
||||
link[doc]: "Documentation" https://github.com/EiffelWebFramework/EWF/tree/master/library/security/http_authorization/README.md
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package http_authorization
|
||||
|
||||
project
|
||||
http_authorization = "http_authorization-safe.ecf"
|
||||
http_authorization = "http_authorization.ecf"
|
||||
|
||||
note
|
||||
title: HTTP Authorization
|
||||
description: "[
|
||||
Class to manipulate HTTP 'Authorization' header value.
|
||||
]"
|
||||
Class to manipulate HTTP 'Authorization' header value.
|
||||
]"
|
||||
|
||||
collection: EWF
|
||||
tags: http,authorization,authentication,web
|
||||
copyright: 2011-2016, Jocelyn Fiat, Eiffel Software and others
|
||||
@@ -17,4 +17,3 @@ note
|
||||
link[source]: "github" https://github.com/EiffelWebFramework/EWF/tree/master/library/server/authentication/http_authorization
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -76,13 +76,13 @@ feature -- Initialization
|
||||
a_http_authorization /= Void implies http_authorization /= Void
|
||||
end
|
||||
|
||||
make_basic_auth (u: READABLE_STRING_32; p: READABLE_STRING_32)
|
||||
make_basic_auth (u: READABLE_STRING_GENERAL; p: READABLE_STRING_GENERAL)
|
||||
-- Create a Basic authentication.
|
||||
do
|
||||
make_custom_auth (u, p, Basic_auth_type)
|
||||
end
|
||||
|
||||
make_custom_auth (u: READABLE_STRING_32; p: READABLE_STRING_32; a_type: READABLE_STRING_8)
|
||||
make_custom_auth (u: READABLE_STRING_GENERAL; p: READABLE_STRING_GENERAL; a_type: READABLE_STRING_8)
|
||||
-- Create a custom `a_type' authentication.
|
||||
require
|
||||
a_type_accepted: a_type.is_case_insensitive_equal (Basic_auth_type)
|
||||
@@ -90,15 +90,20 @@ feature -- Initialization
|
||||
local
|
||||
t: STRING_8
|
||||
utf: UTF_CONVERTER
|
||||
s: STRING_32
|
||||
do
|
||||
login := u
|
||||
password := p
|
||||
create login.make_from_string_general (u)
|
||||
create password.make_from_string_general (p)
|
||||
create t.make_from_string (a_type)
|
||||
t.left_adjust; t.right_adjust
|
||||
type := t
|
||||
if t.is_case_insensitive_equal (Basic_auth_type) then
|
||||
type := Basic_auth_type
|
||||
create http_authorization.make_from_string ("Basic " + (create {BASE64}).encoded_string (utf.string_32_to_utf_8_string_8 (u + {STRING_32} ":" + p)))
|
||||
create s.make_from_string_general (u)
|
||||
s.extend (':')
|
||||
s.append_string_general (p)
|
||||
create http_authorization.make_from_string ("Basic " + (create {BASE64}).encoded_string (utf.string_32_to_utf_8_string_8 (s)))
|
||||
|
||||
elseif t.is_case_insensitive_equal (Digest_auth_type) then
|
||||
type := Digest_auth_type
|
||||
to_implement ("HTTP Authorization %""+ t +"%", not yet implemented")
|
||||
@@ -115,9 +120,9 @@ feature -- Access
|
||||
|
||||
type: READABLE_STRING_8
|
||||
|
||||
login: detachable READABLE_STRING_32
|
||||
login: detachable IMMUTABLE_STRING_32
|
||||
|
||||
password: detachable READABLE_STRING_32
|
||||
password: detachable IMMUTABLE_STRING_32
|
||||
|
||||
feature -- Status report
|
||||
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
package ewsgi
|
||||
|
||||
project
|
||||
ewsgi = "ewsgi-safe.ecf"
|
||||
ewsgi = "ewsgi.ecf"
|
||||
connector_cgi = "connectors/cgi/cgi-safe.ecf"
|
||||
connector_cgi = "connectors/cgi/cgi.ecf"
|
||||
connector_libfcgi = "connectors/libfcgi/libfcgi-safe.ecf"
|
||||
connector_libfcgi = "connectors/libfcgi/libfcgi.ecf"
|
||||
connector_null = "connectors/null/null-safe.ecf"
|
||||
connector_null = "connectors/null/null.ecf"
|
||||
connector_standalone = "connectors/standalone/standalone-safe.ecf"
|
||||
connector_standalone = "connectors/standalone/standalone.ecf"
|
||||
httpd = "connectors/standalone/src/httpd/httpd-safe.ecf"
|
||||
httpd = "connectors/standalone/src/httpd/httpd.ecf"
|
||||
ewsgi_spec = "ewsgi_spec.ecf"
|
||||
connector_nino = "connectors/nino/nino.ecf"
|
||||
|
||||
note
|
||||
title: EWSGI
|
||||
description: "[
|
||||
Eiffel Web Server Gateway Interface (EWSGI) specification, and a few connectors.
|
||||
]"
|
||||
Eiffel Web Server Gateway Interface (EWSGI) specification, and a few connectors.
|
||||
]"
|
||||
|
||||
collection: EWF
|
||||
tags: ewsgi,cgi,web,httpd,ewf
|
||||
copyright: 2011-2016, Jocelyn Fiat, Eiffel Software and others
|
||||
@@ -26,5 +22,5 @@ note
|
||||
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||
link[source]: "github" https://github.com/EiffelWebFramework/EWF/tree/master/library/server/ewsgi
|
||||
link[doc]: "Documentation" https://github.com/EiffelWebFramework/EWF/tree/master/library/server/ewsgi/doc
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -167,7 +167,7 @@ feature -- Element change
|
||||
end
|
||||
|
||||
set_socket_timeout (a_nb_seconds: like socket_timeout)
|
||||
-- Set `socket_timeout' with `a_nb_seconds'
|
||||
-- Set `socket_timeout' with `a_nb_seconds'.
|
||||
do
|
||||
socket_timeout := a_nb_seconds
|
||||
ensure
|
||||
@@ -175,7 +175,7 @@ feature -- Element change
|
||||
end
|
||||
|
||||
set_socket_recv_timeout (a_nb_seconds: like socket_recv_timeout)
|
||||
-- Set `socket_recv_timeout' with `a_nb_seconds'
|
||||
-- Set `socket_recv_timeout' with `a_nb_seconds'.
|
||||
do
|
||||
socket_recv_timeout := a_nb_seconds
|
||||
ensure
|
||||
@@ -183,7 +183,7 @@ feature -- Element change
|
||||
end
|
||||
|
||||
set_keep_alive_timeout (a_seconds: like keep_alive_timeout)
|
||||
-- Set `keep_alive_timeout' with `a_seconds'
|
||||
-- Set `keep_alive_timeout' with `a_seconds'.
|
||||
do
|
||||
keep_alive_timeout := a_seconds
|
||||
ensure
|
||||
@@ -191,7 +191,7 @@ feature -- Element change
|
||||
end
|
||||
|
||||
set_max_keep_alive_requests (nb: like max_keep_alive_requests)
|
||||
-- Set `max_keep_alive_requests' with `nb'
|
||||
-- Set `max_keep_alive_requests' with `nb'.
|
||||
do
|
||||
max_keep_alive_requests := nb
|
||||
ensure
|
||||
@@ -254,7 +254,7 @@ feature -- Element change
|
||||
end
|
||||
|
||||
mark_secure
|
||||
-- Set is_secure in True
|
||||
-- Set is_secure in True.
|
||||
do
|
||||
set_is_secure (True)
|
||||
ensure
|
||||
@@ -287,7 +287,7 @@ feature -- Element change
|
||||
end
|
||||
|
||||
set_secure_protocol (a_version: NATURAL)
|
||||
-- Set `secure_protocol' with `a_version'
|
||||
-- Set `secure_protocol' with `a_version'.
|
||||
do
|
||||
secure_protocol := a_version
|
||||
ensure
|
||||
@@ -295,18 +295,19 @@ feature -- Element change
|
||||
end
|
||||
|
||||
set_secure_protocol_from_string (a_ssl_version: READABLE_STRING_GENERAL)
|
||||
-- Set `secure_protocol' with `a_ssl_version'
|
||||
-- Set `secure_protocol' with `a_ssl_version'.
|
||||
do
|
||||
if a_ssl_version.is_case_insensitive_equal ("ssl_2_3") then
|
||||
set_secure_protocol_to_ssl_2_or_3
|
||||
elseif a_ssl_version.is_case_insensitive_equal ("tls_1_0") then
|
||||
set_secure_protocol_to_tls_1_0
|
||||
if a_ssl_version.is_case_insensitive_equal ("tls_1_2") then
|
||||
set_secure_protocol_to_tls_1_2
|
||||
elseif a_ssl_version.is_case_insensitive_equal ("tls_1_1") then
|
||||
set_secure_protocol_to_tls_1_1
|
||||
elseif a_ssl_version.is_case_insensitive_equal ("tls_1_2") then
|
||||
set_secure_protocol_to_tls_1_2
|
||||
elseif a_ssl_version.is_case_insensitive_equal ("tls_1_0") then
|
||||
set_secure_protocol_to_tls_1_0
|
||||
elseif a_ssl_version.is_case_insensitive_equal ("dtls_1_0") then
|
||||
set_secure_protocol_to_dtls_1_0
|
||||
elseif a_ssl_version.is_case_insensitive_equal ("ssl_2_3") then
|
||||
-- Obsolete!
|
||||
set_secure_protocol_to_ssl_2_or_3
|
||||
else -- Default
|
||||
set_secure_protocol_to_tls_1_2
|
||||
end
|
||||
@@ -316,6 +317,8 @@ feature -- SSL Helpers
|
||||
|
||||
set_secure_protocol_to_ssl_2_or_3
|
||||
-- Set `secure_protocol' with `Ssl_23'.
|
||||
obsolete
|
||||
"Use `set_secure_protocol_to_tls_1_2` [2017-06-23]."
|
||||
deferred
|
||||
end
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
<exclude>/\.svn$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="http_network" location="..\..\network\http_network\http_network.ecf" readonly="false"/>
|
||||
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
||||
@@ -16,8 +14,11 @@
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</library>
|
||||
<library name="openssl" location="$ISE_LIBRARY\unstable\library\network\openssl\openssl.ecf">
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
<version type="compiler" min="17.10.0.0"/>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</library>
|
||||
<library name="thread" location="$ISE_LIBRARY\library\thread\thread.ecf">
|
||||
@@ -35,16 +36,12 @@
|
||||
<cluster name="no_ssl" location="$|no_ssl\" recursive="true">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" excluded_value="true"/>
|
||||
<custom name="httpd_ssl_enabled" excluded_value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="ssl" location="$|ssl\" recursive="true">
|
||||
<condition>
|
||||
<custom name="ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
<condition>
|
||||
<custom name="httpd_ssl_enabled" value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="concurrency_none" location="$|concurrency\none\" recursive="true">
|
||||
<condition>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
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.
|
||||
]"
|
||||
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
|
||||
|
||||
@@ -36,9 +36,16 @@ feature -- Access
|
||||
feature -- SSL Helpers
|
||||
|
||||
set_secure_protocol_to_ssl_2_or_3
|
||||
-- Set `secure_protocol' with `Ssl_23'.
|
||||
-- Set `ssl_protocol' with `Ssl_23'.
|
||||
-- Protocol not supported anymore.
|
||||
obsolete
|
||||
"Use set_secure_protocol_to_tls_1_2 [2017-06-23]."
|
||||
local
|
||||
err: DEVELOPER_EXCEPTION
|
||||
do
|
||||
set_secure_protocol ({SSL_PROTOCOL}.Ssl_23)
|
||||
create err
|
||||
err.set_description ("SSL_2 or SSL_3 are not supported anymore, upgrate to TLS set_secure_protocol_to_tls_1_2")
|
||||
err.raise
|
||||
end
|
||||
|
||||
set_secure_protocol_to_tls_1_0
|
||||
@@ -67,7 +74,7 @@ feature -- SSL Helpers
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -4,16 +4,16 @@ setup
|
||||
compile_library = Clib
|
||||
|
||||
project
|
||||
libfcgi = "libfcgi-safe.ecf"
|
||||
libfcgi = "libfcgi.ecf"
|
||||
|
||||
note
|
||||
title: Eiffel libfcgi wrapper
|
||||
description: "[
|
||||
Wrapper on modified libfcgi.
|
||||
(modification: added 64 bits support)
|
||||
It brings implementation for FCGI protocol.
|
||||
]"
|
||||
Wrapper on modified libfcgi.
|
||||
(modification: added 64 bits support)
|
||||
It brings implementation for FCGI protocol.
|
||||
]"
|
||||
|
||||
collection: EWF
|
||||
tags: fcgi,libfcgi,cgi,http,web,ewf
|
||||
copyright: 2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others
|
||||
|
||||
@@ -1,40 +1,32 @@
|
||||
|
||||
package wsf
|
||||
|
||||
project
|
||||
wsf = "wsf-safe.ecf"
|
||||
wsf = "wsf.ecf"
|
||||
wsf_extension = "wsf_extension-safe.ecf"
|
||||
wsf_extension = "wsf_extension.ecf"
|
||||
wsf_policy_driven = "wsf_policy_driven-safe.ecf"
|
||||
wsf_policy_driven = "wsf_policy_driven.ecf"
|
||||
wsf_router_context = "wsf_router_context-safe.ecf"
|
||||
wsf_router_context = "wsf_router_context.ecf"
|
||||
wsf_session = "wsf_session-safe.ecf"
|
||||
wsf_session = "wsf_session.ecf"
|
||||
wsf_cgi = "connector/cgi-safe.ecf"
|
||||
wsf_cgi = "connector/cgi.ecf"
|
||||
wsf_libfcgi = "connector/libfcgi-safe.ecf"
|
||||
wsf_libfcgi = "connector/libfcgi.ecf"
|
||||
wsf_openshift = "connector/openshift-safe.ecf"
|
||||
default_cgi = "default/cgi-safe.ecf"
|
||||
default_cgi = "default/cgi.ecf"
|
||||
default_libfcgi = "default/libfcgi-safe.ecf"
|
||||
default_libfcgi = "default/libfcgi.ecf"
|
||||
default_openshift = "default/openshift-safe.ecf"
|
||||
wsf_standalone = "connector/standalone-safe.ecf"
|
||||
default_openshift = "default/openshift.ecf"
|
||||
wsf_standalone = "connector/standalone.ecf"
|
||||
default_standalone = "default/standalone-safe.ecf"
|
||||
default_standalone = "default/standalone.ecf"
|
||||
|
||||
wsf_all = "connector/all.ecf"
|
||||
wsf_nino = "connector/nino.ecf"
|
||||
wsf_openshift = "connector/openshift.ecf"
|
||||
wsf_standalone_websocket = "connector/standalone_websocket.ecf"
|
||||
default_nino = "default/nino.ecf"
|
||||
|
||||
note
|
||||
title: Web Server Foundation
|
||||
description: "[
|
||||
Core of the Eiffel Web Framework (EWF).
|
||||
Provide the request, response, router, ... interfaces.
|
||||
The foundation to build web server application.
|
||||
]"
|
||||
Core of the Eiffel Web Framework (EWF).
|
||||
Provide the request, response, router, ... interfaces.
|
||||
The foundation to build web server application.
|
||||
]"
|
||||
|
||||
tags: ewf,server,httpd,request,connector,web
|
||||
collection: EWF
|
||||
copyright: 2011-2016, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others
|
||||
@@ -44,4 +36,3 @@ note
|
||||
link[doc]: "Documentation" http://eiffelwebframework.github.io/EWF/
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ feature {NONE} -- Initialization
|
||||
|
||||
feature -- Access
|
||||
|
||||
default_value: detachable READABLE_STRING_GENERAL
|
||||
default_value: detachable READABLE_STRING_32
|
||||
|
||||
rows: INTEGER
|
||||
|
||||
@@ -54,9 +54,13 @@ feature -- Element change
|
||||
end
|
||||
end
|
||||
|
||||
set_default_value (v: like default_value)
|
||||
set_default_value (v: detachable READABLE_STRING_GENERAL)
|
||||
do
|
||||
default_value := v
|
||||
if v = Void then
|
||||
default_value := Void
|
||||
else
|
||||
default_value := v.as_string_32
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description : "Objects containing widget WSF_WIDGET objects, and add specific form support (notion of form fields)."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_FORM_COMPOSITE
|
||||
|
||||
@@ -48,7 +48,9 @@ feature -- Access
|
||||
|
||||
item (a_name: READABLE_STRING_GENERAL): detachable WSF_VALUE
|
||||
do
|
||||
Result := items.item (a_name.as_string_8)
|
||||
if a_name.is_valid_as_string_8 then
|
||||
Result := items.item (a_name.to_string_8)
|
||||
end
|
||||
end
|
||||
|
||||
string_item (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
|
||||
|
||||
@@ -39,7 +39,7 @@ feature -- Element Change
|
||||
set_max (a_val: INTEGER)
|
||||
-- Set `max' with `a_val'.
|
||||
do
|
||||
set_max_string(a_val.out)
|
||||
set_max_string (a_val.out)
|
||||
ensure
|
||||
max_set: attached max as l_max implies l_max.same_string (a_val.out)
|
||||
end
|
||||
@@ -94,7 +94,6 @@ feature -- Element Change
|
||||
step_set: attached step as l_step implies l_step.same_string_general (a_val)
|
||||
end
|
||||
|
||||
|
||||
feature {NONE} -- Conversion
|
||||
|
||||
append_numeric_input_attributes_to (a_target: STRING)
|
||||
@@ -103,7 +102,7 @@ feature {NONE} -- Conversion
|
||||
--min
|
||||
if attached min as l_min then
|
||||
a_target.append (" min=%"")
|
||||
a_target.append(l_min)
|
||||
a_target.append (l_min)
|
||||
a_target.append_character ('%"')
|
||||
end
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ feature {NONE} -- Initialization
|
||||
name := a_name
|
||||
end
|
||||
|
||||
make_with_text (a_name: like name; a_text: READABLE_STRING_32)
|
||||
make_with_text (a_name: like name; a_text: READABLE_STRING_GENERAL)
|
||||
do
|
||||
make (a_name)
|
||||
set_text_value (a_text)
|
||||
@@ -44,7 +44,7 @@ feature -- Access
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_text_value (s: detachable READABLE_STRING_32)
|
||||
set_text_value (s: detachable READABLE_STRING_GENERAL)
|
||||
do
|
||||
set_default_value (s)
|
||||
end
|
||||
@@ -73,9 +73,13 @@ feature -- Element change
|
||||
end
|
||||
end
|
||||
|
||||
set_default_value (v: like default_value)
|
||||
set_default_value (v: detachable READABLE_STRING_GENERAL)
|
||||
do
|
||||
default_value := v
|
||||
if v = Void then
|
||||
default_value := Void
|
||||
else
|
||||
default_value := v.as_string_32
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
@@ -35,12 +35,17 @@ feature -- Access
|
||||
|
||||
feature -- Change element
|
||||
|
||||
set_placeholder (a_placeholder: READABLE_STRING_32)
|
||||
set_placeholder (a_placeholder: detachable READABLE_STRING_GENERAL)
|
||||
-- Set `placeholder' with `a_placeholder'.
|
||||
do
|
||||
placeholder := a_placeholder
|
||||
if a_placeholder = Void then
|
||||
placeholder := Void
|
||||
else
|
||||
placeholder := a_placeholder.as_string_32
|
||||
end
|
||||
ensure
|
||||
placeholder_set: attached placeholder as l_placeholder implies l_placeholder = a_placeholder
|
||||
placeholder_set: (a_placeholder = Void implies placeholder = Void)
|
||||
or (a_placeholder /= Void implies (attached placeholder as l_placeholder and then a_placeholder.same_string (l_placeholder)))
|
||||
end
|
||||
|
||||
enable_autofocus
|
||||
@@ -91,16 +96,21 @@ feature -- Change element
|
||||
required_flase: not required
|
||||
end
|
||||
|
||||
set_pattern (a_pattern: READABLE_STRING_32)
|
||||
set_pattern (a_pattern: READABLE_STRING_GENERAL)
|
||||
-- Set `pattern' with `a_pattern'.
|
||||
-- Example:[0-9][A-Z]{3}
|
||||
-- Check HTML5 patterns site.
|
||||
note
|
||||
EIS: "name=HTML5 Patterns", "src=http://html5pattern.com/"
|
||||
do
|
||||
pattern := a_pattern
|
||||
if a_pattern = Void then
|
||||
pattern := Void
|
||||
else
|
||||
pattern := a_pattern.as_string_32
|
||||
end
|
||||
ensure
|
||||
pattern_set: attached pattern as l_pattern implies l_pattern = a_pattern
|
||||
pattern_set: (a_pattern = Void implies pattern = Void) or
|
||||
a_pattern /= Void implies attached pattern as l_pattern and then a_pattern.same_string (l_pattern)
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ feature -- Access
|
||||
|
||||
feature -- Element Change
|
||||
|
||||
|
||||
set_formnovalidate
|
||||
-- Set formnovalidate to True.
|
||||
do
|
||||
@@ -60,49 +59,69 @@ feature -- Element Change
|
||||
formnovalidate_false: not formnovalidate
|
||||
end
|
||||
|
||||
set_formaction (a_action: READABLE_STRING_GENERAL)
|
||||
set_formaction (a_action: detachable READABLE_STRING_GENERAL)
|
||||
-- Set `formaction' with `a_action'.
|
||||
-- Example:<input type="submit" value="Submit" formaction="/users">
|
||||
require
|
||||
is_valid_as_string_8: a_action.is_valid_as_string_8
|
||||
is_valid_as_string_8: a_action /= Void implies a_action.is_valid_as_string_8
|
||||
do
|
||||
formaction := a_action.to_string_8
|
||||
if a_action = Void then
|
||||
formaction := Void
|
||||
else
|
||||
formaction := a_action.to_string_8
|
||||
end
|
||||
ensure
|
||||
formaction_set: attached formaction as l_action implies l_action = a_action
|
||||
formaction_set: (a_action = Void implies formaction = Void)
|
||||
or (a_action /= Void implies (attached formaction as l_action and then a_action.same_string (l_action)))
|
||||
end
|
||||
|
||||
set_formenctype (a_enctype: READABLE_STRING_GENERAL)
|
||||
set_formenctype (a_enctype: detachable READABLE_STRING_GENERAL)
|
||||
-- Set `formenctype' with `a_enctype'.
|
||||
-- Example: <input type="submit" value="Submit" formenctype="application/x-www-form-urlencoded">
|
||||
require
|
||||
is_valid_as_string_8: a_enctype.is_valid_as_string_8
|
||||
is_valid_as_string_8: a_enctype /= Void implies a_enctype.is_valid_as_string_8
|
||||
do
|
||||
formenctype := a_enctype.to_string_8
|
||||
if a_enctype = Void then
|
||||
formenctype := Void
|
||||
else
|
||||
formenctype := a_enctype.to_string_8
|
||||
end
|
||||
ensure
|
||||
formenctype_set: attached formenctype as l_enctype implies l_enctype = a_enctype
|
||||
formenctype_set: (a_enctype = Void implies formenctype = Void)
|
||||
or (a_enctype /= Void implies (attached formenctype as l_enctype and then a_enctype.same_string (l_enctype)))
|
||||
end
|
||||
|
||||
set_formmethod (a_method: READABLE_STRING_GENERAL)
|
||||
set_formmethod (a_method: detachable READABLE_STRING_GENERAL)
|
||||
-- Set `formmethod' with `a_method'.
|
||||
-- Example: <input type="submit" value="Submit" formmethod="POST">
|
||||
--! require is_valid_method: [PUT, POST, DELETE, GET, ...]
|
||||
require
|
||||
is_valid_as_string_8: a_method.is_valid_as_string_8
|
||||
is_valid_as_string_8: a_method /= Void implies a_method.is_valid_as_string_8
|
||||
do
|
||||
formmethod := a_method.to_string_8
|
||||
if a_method = Void then
|
||||
formmethod := Void
|
||||
else
|
||||
formmethod := a_method.to_string_8
|
||||
end
|
||||
ensure
|
||||
formmethod_set: attached formmethod as l_method implies l_method = a_method
|
||||
formmethod_set: (a_method = Void implies formmethod = Void)
|
||||
or (a_method /= Void implies (attached formmethod as l_method and then a_method.same_string (l_method)))
|
||||
end
|
||||
|
||||
set_formtarget (a_target: READABLE_STRING_GENERAL)
|
||||
set_formtarget (a_target: detachable READABLE_STRING_GENERAL)
|
||||
-- Set `formtarget' with `a_target'.
|
||||
-- Example: <input type="submit" value="Submit" formtarget="_self">
|
||||
require
|
||||
is_valid_as_string_8: a_target.is_valid_as_string_8
|
||||
is_valid_as_string_8: a_target /= Void implies a_target.is_valid_as_string_8
|
||||
do
|
||||
formtarget := a_target.to_string_8
|
||||
if a_target = Void then
|
||||
formtarget := Void
|
||||
else
|
||||
formtarget := a_target.to_string_8
|
||||
end
|
||||
ensure
|
||||
formtarget_set: attached formtarget as l_target implies l_target = a_target
|
||||
formtarget_set: (a_target = Void implies formtarget = Void)
|
||||
or (a_target /= Void implies (attached formtarget as l_target and then a_target.same_string (l_target)))
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
note
|
||||
description : "Objects that ..."
|
||||
author : "$Author$"
|
||||
date : "$Date$"
|
||||
revision : "$Revision$"
|
||||
description : "Objects containing WSF_WIDGET objects."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
WSF_WIDGET_COMPOSITE
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
package encoder
|
||||
|
||||
project
|
||||
encoder = "encoder-safe.ecf"
|
||||
encoder = "encoder.ecf"
|
||||
|
||||
note
|
||||
title: Text encoders
|
||||
description: "[
|
||||
Text encoders used in web technologies:
|
||||
- HTML encoder
|
||||
- XML encoder
|
||||
- JSON encoder
|
||||
- UTF8
|
||||
- BASE64
|
||||
]"
|
||||
Text encoders used in web technologies:
|
||||
- HTML encoder
|
||||
- XML encoder
|
||||
- JSON encoder
|
||||
- UTF8
|
||||
- BASE64
|
||||
]"
|
||||
|
||||
collection: EWF
|
||||
tags: html,xml,percent encoding,web,json,utf
|
||||
copyright: 2011-2016, Jocelyn Fiat, Eiffel Software and others
|
||||
@@ -23,4 +23,3 @@ note
|
||||
link[doc]: "Documentation" https://github.com/EiffelWebFramework/EWF/blob/master/library/text/encoder/README.md
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package feed
|
||||
|
||||
project
|
||||
feed = "feed-safe.ecf"
|
||||
feed = "feed.ecf"
|
||||
|
||||
note
|
||||
title: Eiffel FEED parser
|
||||
description: "[
|
||||
RSS2.0 and ATOM feed parser.
|
||||
Feed visitor including HTML generation from FEED Eiffel objects.
|
||||
]"
|
||||
RSS2.0 and ATOM feed parser.
|
||||
Feed visitor including HTML generation from FEED Eiffel objects.
|
||||
]"
|
||||
|
||||
tags: rss,atom,feed,html,generator,parser
|
||||
copyright: 2011-2016, Jocelyn Fiat, Eiffel Software and others
|
||||
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package uri_template
|
||||
|
||||
project
|
||||
uri_template = "uri_template-safe.ecf"
|
||||
uri_template = "uri_template.ecf"
|
||||
|
||||
note
|
||||
title: URI Template
|
||||
description: "[
|
||||
Implement URI Template as described at http://tools.ietf.org/rfc/rfc6570.txt
|
||||
Implement URI Template as described at http://tools.ietf.org/rfc/rfc6570.txt
|
||||
|
||||
Support for URI template string expansion
|
||||
But also partial URI Template matching
|
||||
]"
|
||||
|
||||
Support for URI template string expansion
|
||||
But also partial URI Template matching
|
||||
]"
|
||||
collection: EWF
|
||||
tags: uri template,router,generator,url
|
||||
copyright: 2011-2016, Jocelyn Fiat, Javier Velilla, Eiffel Software and others
|
||||
@@ -21,4 +21,3 @@ note
|
||||
link[doc]: "Documentation" https://github.com/EiffelWebFramework/EWF/tree/master/library/text/parser/uri_template/README.md
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
package error
|
||||
|
||||
project
|
||||
error = "error-safe.ecf"
|
||||
error = "error.ecf"
|
||||
|
||||
note
|
||||
title: Error framework
|
||||
description: "[
|
||||
Errors and associated handler, to manage errors and also provides a way to synchronize one or many error handlers.
|
||||
This is convenient to propagate error from a layer to another without adding unwanted dependencies.
|
||||
]"
|
||||
Errors and associated handler, to manage errors and also provides a way to synchronize one or many error handlers.
|
||||
This is convenient to propagate error from a layer to another without adding unwanted dependencies.
|
||||
]"
|
||||
|
||||
collection: EWF
|
||||
tags: error,framework
|
||||
license: Eiffel Forum License v2
|
||||
copyright: Jocelyn Fiat, Eiffel Software and others.
|
||||
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||
link[source]: "github" https://github.com/EiffelWebFramework/EWF/tree/master/library/utility/general/error
|
||||
link[source]: "github" https://github.com/EiffelWebFramework/EWF/tree/master/library/utility/general/error
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
</option>
|
||||
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone.ecf" readonly="false" use_application_options="true"/>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
<override name="override" location="override\" recursive="true"/>
|
||||
</target>
|
||||
<target name="hello_cgi" extends="hello_dev">
|
||||
<library name="default_cgi" location="..\..\library\server\wsf\default\cgi.ecf"/>
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<capability>
|
||||
<catcall_detection use="none"/>
|
||||
</capability>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
||||
<cluster name="src" location=".\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
253
tests/standalone/client/test_app.e
Normal file
253
tests/standalone/client/test_app.e
Normal file
@@ -0,0 +1,253 @@
|
||||
note
|
||||
description: "[
|
||||
Enter class description here!
|
||||
]"
|
||||
|
||||
class
|
||||
TEST_APP
|
||||
|
||||
inherit
|
||||
SHARED_EXECUTION_ENVIRONMENT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Instantiate Current object.
|
||||
local
|
||||
h, res: STRING
|
||||
i: INTEGER
|
||||
l_test_name: detachable READABLE_STRING_GENERAL
|
||||
choices: HASH_TABLE [READABLE_STRING_GENERAL, INTEGER]
|
||||
do
|
||||
create h.make_empty
|
||||
h.append_character ((0).to_character_8)
|
||||
h.append_character ((0).to_character_8)
|
||||
h.append_character ((255).to_character_8)
|
||||
h.append_character ((255).to_character_8)
|
||||
|
||||
i := 0
|
||||
if attached execution_environment.arguments.argument (1) as tn then
|
||||
l_test_name := tn
|
||||
else
|
||||
create choices.make (tests.count)
|
||||
across
|
||||
tests as ic
|
||||
loop
|
||||
i := i + 1
|
||||
choices.force (ic.key, i)
|
||||
print (i.out + " - " + ic.key.out + "%N")
|
||||
end
|
||||
print (" > ")
|
||||
io.read_line
|
||||
res := io.last_string
|
||||
res.adjust
|
||||
if
|
||||
res.is_integer and then
|
||||
attached choices [res.to_integer] as tn
|
||||
then
|
||||
l_test_name := tn
|
||||
end
|
||||
end
|
||||
if
|
||||
l_test_name /= Void and then
|
||||
attached tests [l_test_name] as proc
|
||||
then
|
||||
proc.call ()
|
||||
else
|
||||
print ("Quit...%N")
|
||||
end
|
||||
end
|
||||
|
||||
port_number: INTEGER = 9090
|
||||
|
||||
hostname: STRING = "localhost"
|
||||
|
||||
has_error: BOOLEAN
|
||||
|
||||
tests: STRING_TABLE [PROCEDURE]
|
||||
once
|
||||
create Result.make (10)
|
||||
Result.force (agent cli_execute_get_request, "get_request")
|
||||
Result.force (agent execute_get_request (1, 0), "get_request (1,0)")
|
||||
Result.force (agent execute_get_request (10, 0), "get_request (10,0)")
|
||||
Result.force (agent execute_get_request (1, 10_000), "get_request (1, 10000)")
|
||||
Result.force (agent execute_get_request (10, 10_000), "get_request (10, 10000)")
|
||||
Result.force (agent execute_wait_for_ever, "wait_for_ever")
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
wait_ms (a_delay_ms: INTEGER; m: detachable READABLE_STRING_8)
|
||||
local
|
||||
i64: INTEGER_64
|
||||
do
|
||||
if a_delay_ms > 0 then
|
||||
if has_error then
|
||||
print ("[ERROR/WAIT] Skipped due to previous error%N")
|
||||
else
|
||||
|
||||
i64 := a_delay_ms.as_integer_64 * {INTEGER_64} 1_000_000
|
||||
if m /= Void then
|
||||
print ("[WAIT] " + i64.out + " nanoseconds -> " + m + "%N")
|
||||
else
|
||||
print ("[WAIT] " + i64.out + " nanoseconds.%N")
|
||||
end
|
||||
execution_environment.sleep (i64) -- nanoseconds
|
||||
print ("[WAIT] done.%N")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cli_execute_get_request
|
||||
local
|
||||
i,n: INTEGER
|
||||
rq_nb: INTEGER
|
||||
sl_val: INTEGER
|
||||
do
|
||||
if attached execution_environment.arguments as args then
|
||||
n := args.argument_count
|
||||
rq_nb := 1
|
||||
sl_val := 0
|
||||
i := 1
|
||||
if n > i then
|
||||
if args.argument (i).is_case_insensitive_equal_general ("get_request") then
|
||||
if n >= i + 1 then
|
||||
rq_nb := args.argument (i + 1).to_integer
|
||||
if n >= i + 2 then
|
||||
sl_val := args.argument (i + 2).to_integer
|
||||
end
|
||||
end
|
||||
execute_get_request (rq_nb, sl_val)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
execute_get_request (rq_nb: INTEGER; a_delay_ms: INTEGER)
|
||||
require
|
||||
rq_nb > 0
|
||||
local
|
||||
l_socket: NETWORK_STREAM_SOCKET
|
||||
l_packet: PACKET
|
||||
l_header_done, l_done: BOOLEAN
|
||||
line, txt: READABLE_STRING_8
|
||||
h: STRING
|
||||
len: INTEGER
|
||||
i: INTEGER
|
||||
do
|
||||
create l_socket.make_client_by_port (port_number, hostname)
|
||||
l_socket.connect
|
||||
|
||||
from
|
||||
i := rq_nb
|
||||
until
|
||||
i <= 0
|
||||
loop
|
||||
i := i - 1
|
||||
|
||||
print ("GET /test/"+ i.out +" HTTP/1.1%N")
|
||||
-- socket_put_string (l_socket, "GET /test/"+ i.out +" HTTP/1.1%R%N")
|
||||
|
||||
socket_put_string (l_socket, "GET /test/"+ i.out)
|
||||
wait_ms (a_delay_ms, "inside GET request line")
|
||||
socket_put_string (l_socket, " HTTP/1.1%R%N")
|
||||
wait_ms (a_delay_ms, "before Host")
|
||||
socket_put_string (l_socket, "Host: localhost:9090%R%N")
|
||||
wait_ms (a_delay_ms, "before Accept")
|
||||
socket_put_string (l_socket, "Accept: */*%R%N")
|
||||
wait_ms (a_delay_ms, "before CRNL")
|
||||
socket_put_string (l_socket, "%R%N")
|
||||
wait_ms (a_delay_ms, "before reading!")
|
||||
|
||||
if not has_error then
|
||||
from
|
||||
l_done := False
|
||||
l_header_done := False
|
||||
create h.make_empty
|
||||
until
|
||||
l_done
|
||||
loop
|
||||
if l_header_done then
|
||||
l_socket.read_stream (len)
|
||||
txt := l_socket.last_string
|
||||
print ("BODY:%N")
|
||||
print (txt)
|
||||
print ("%N")
|
||||
if txt.count /= len then
|
||||
print ("BAD len: " + txt.count.out + " /= " + len.out + "%N")
|
||||
end
|
||||
l_done := True
|
||||
else
|
||||
l_socket.read_line
|
||||
line := l_socket.last_string
|
||||
if l_socket.was_error then
|
||||
l_done := True
|
||||
elseif line.is_empty or (line.count = 1 and line[1] = '%R') then
|
||||
l_header_done := True
|
||||
else
|
||||
if line.starts_with_general ("Content-Length:") then
|
||||
len := line.substring (16, line.count).to_integer
|
||||
end
|
||||
h.append (line)
|
||||
h.append ("%R%N")
|
||||
|
||||
print ("HEADER:")
|
||||
print (line)
|
||||
print ("%N")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
execute_wait_for_ever
|
||||
local
|
||||
l_socket: NETWORK_STREAM_SOCKET
|
||||
l_packet: PACKET
|
||||
do
|
||||
create l_socket.make_client_by_port(9090, "localhost")
|
||||
l_socket.connect
|
||||
|
||||
create l_packet.make(1)
|
||||
l_packet.put_element('a', 0)
|
||||
|
||||
l_socket.send(l_packet, 0)
|
||||
|
||||
from
|
||||
|
||||
until
|
||||
not l_socket.is_connected
|
||||
loop
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
socket_put_string (a_socket: NETWORK_STREAM_SOCKET; s: STRING_8)
|
||||
local
|
||||
retried: BOOLEAN
|
||||
t: STRING
|
||||
i: INTEGER
|
||||
do
|
||||
if has_error then
|
||||
create t.make_from_string (s)
|
||||
i := t.index_of ('%N', 1)
|
||||
if i > 0 then
|
||||
t.keep_head (i - 1)
|
||||
end
|
||||
t.adjust
|
||||
print ("[ERROR] Skip put_string ("+ s +"..)%N")
|
||||
elseif retried then
|
||||
has_error := True
|
||||
else
|
||||
a_socket.put_string (s)
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user