Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b81f690d0c | ||
|
|
2748e1d9ee | ||
|
|
27ee20f99b | ||
|
|
9a3164df70 | ||
|
|
02383810b4 | ||
|
|
dbf5e76047 | ||
|
|
5c31905427 | ||
|
|
c7ef652322 | ||
|
|
7feb45b549 | ||
|
|
5bbd031275 | ||
|
|
90e60fad26 | ||
|
|
98c20ee7c1 | ||
|
|
0b99e84728 | ||
|
|
9e5e8bb1bf | ||
|
|
10a83c6ad8 | ||
|
|
1ec3b8e7a4 |
+4
-10
@@ -7,20 +7,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
|
- jwt: new JSON Web Token (JWT) library (supports for claim exp, iat, nbf, iss, aud).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- http_network:
|
|
||||||
Integrated changes on SOCKET so that EiffelWeb can be compiled with 16.05 to 17.05 and after.
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
### Removed
|
### Removed
|
||||||
### Fixed
|
### Fixed
|
||||||
- http_client:
|
- Removed a few obsolete calls.
|
||||||
Improved query and form data encoding (based on a very early version of the general URI percent-encoding rules).
|
- `http_client`: Added support for multiple file in form data. Made clear what is the meaning of `upload_filename`, `upload_data` and `form_data`.
|
||||||
- now correct encoding of space by '%20' in path segment, and '+' in query parameters.
|
|
||||||
Unify and fixed query parameters handling for libcurl and net implementation.
|
|
||||||
Fixed file uploading (various issue in libcurl, and net implementation).
|
|
||||||
Fixed form multipart encoding by using correctly the boundary.
|
|
||||||
- Code cleaning:
|
|
||||||
Removed many obsolete calls, and added timestamp on EiffelWeb obsolete features to benefit from upcoming improvement on the EiffelStudio Inspector tool.
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
|
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
|
||||||
<cluster name="src" location=".\src\">
|
<cluster name="src" location=".\src\">
|
||||||
<cluster name="implementation" location="$|implementation" recursive="true" hidden="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_null" location="$|spec\null\" recursive="true"/>
|
||||||
<cluster name="spec_net" location="$|spec\net\">
|
<cluster name="spec_net" location="$|spec\net\">
|
||||||
<condition>
|
<condition>
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf"/>
|
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf"/>
|
||||||
<cluster name="src" location=".\src\">
|
<cluster name="src" location=".\src\">
|
||||||
<cluster name="implementation" location="$|implementation" recursive="true" hidden="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_null" location="$|spec\null\" recursive="true"/>
|
||||||
<cluster name="spec_net" location="$|spec\net\">
|
<cluster name="spec_net" location="$|spec\net\">
|
||||||
<condition>
|
<condition>
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
|
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
|
||||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
|
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
|
||||||
<cluster name="src" location=".\src\">
|
<cluster name="src" location=".\src\">
|
||||||
|
<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="spec_libcurl" location="$|spec\libcurl\" recursive="true"/>
|
||||||
<cluster name="default_libcurl" location="$|default\libcurl\"/>
|
<cluster name="default_libcurl" location="$|default\libcurl\"/>
|
||||||
</cluster>
|
</cluster>
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
||||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf"/>
|
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf"/>
|
||||||
<cluster name="src" location=".\src\">
|
<cluster name="src" location=".\src\">
|
||||||
|
<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="spec_libcurl" location="$|spec\libcurl\" recursive="true"/>
|
||||||
<cluster name="default_libcurl" location="$|default\libcurl\"/>
|
<cluster name="default_libcurl" location="$|default\libcurl\"/>
|
||||||
</cluster>
|
</cluster>
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
</library>
|
</library>
|
||||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
|
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
|
||||||
<cluster name="src" location=".\src\">
|
<cluster name="src" location=".\src\">
|
||||||
|
<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="spec_net" location="$|spec\net\">
|
||||||
<cluster name="net_implementation" location="$|implementation\" hidden="true"/>
|
<cluster name="net_implementation" location="$|implementation\" hidden="true"/>
|
||||||
</cluster>
|
</cluster>
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
</library>
|
</library>
|
||||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf"/>
|
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri.ecf"/>
|
||||||
<cluster name="src" location=".\src\">
|
<cluster name="src" location=".\src\">
|
||||||
|
<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="spec_net" location="$|spec\net\">
|
||||||
<cluster name="net_implementation" location="$|implementation\" hidden="true"/>
|
<cluster name="net_implementation" location="$|implementation\" hidden="true"/>
|
||||||
</cluster>
|
</cluster>
|
||||||
|
|||||||
@@ -16,8 +16,19 @@ feature -- Access
|
|||||||
deferred
|
deferred
|
||||||
end
|
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
|
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)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -58,11 +58,11 @@ feature -- Access
|
|||||||
-- Specific headers to use in addition to the one set in the related HTTP_CLIENT_SESSION
|
-- Specific headers to use in addition to the one set in the related HTTP_CLIENT_SESSION
|
||||||
--| note: the value from Current context override the one from the session in case of conflict
|
--| note: the value from Current context override the one from the session in case of conflict
|
||||||
|
|
||||||
query_parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_32]
|
query_parameters: HTTP_CLIENT_REQUEST_QUERY_PARAMETERS
|
||||||
-- Query parameters to be appended to the url
|
-- Query parameters to be appended to the url
|
||||||
--| note: if the url already contains a query_string, the `query_parameters' will be appended to the url
|
--| note: if the url already contains a query_string, the `query_parameters' will be appended to the url
|
||||||
|
|
||||||
form_parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_32]
|
form_parameters: HTTP_CLIENT_REQUEST_FORM_PARAMETERS
|
||||||
-- Form parameters
|
-- Form parameters
|
||||||
|
|
||||||
upload_data: detachable READABLE_STRING_8
|
upload_data: detachable READABLE_STRING_8
|
||||||
@@ -145,13 +145,25 @@ feature -- Element change
|
|||||||
add_query_parameter (k: READABLE_STRING_GENERAL; v: READABLE_STRING_GENERAL)
|
add_query_parameter (k: READABLE_STRING_GENERAL; v: READABLE_STRING_GENERAL)
|
||||||
-- Add a query parameter `k=v'.
|
-- Add a query parameter `k=v'.
|
||||||
do
|
do
|
||||||
query_parameters.force (v.to_string_32, k.to_string_32)
|
query_parameters.force (create {HTTP_CLIENT_REQUEST_STRING_PARAMETER}.make (k, v))
|
||||||
end
|
end
|
||||||
|
|
||||||
add_form_parameter (k: READABLE_STRING_GENERAL; v: READABLE_STRING_GENERAL)
|
add_form_parameter (k: READABLE_STRING_GENERAL; v: READABLE_STRING_GENERAL)
|
||||||
-- Add a form parameter `k'= `v'.
|
-- Add a form parameter `k'= `v'.
|
||||||
do
|
do
|
||||||
form_parameters.force (v.to_string_32, k.to_string_32)
|
form_parameters.force (create {HTTP_CLIENT_REQUEST_STRING_PARAMETER}.make (k, v))
|
||||||
|
end
|
||||||
|
|
||||||
|
add_file_form_parameter (k: READABLE_STRING_GENERAL; a_location: READABLE_STRING_GENERAL; a_content_type: detachable READABLE_STRING_8)
|
||||||
|
-- Add a form file parameter named `k`, located at `a_location`, with optional content type `a_content_type`.
|
||||||
|
require
|
||||||
|
has_no_upload_data_or_filename: not has_upload_data and not has_upload_filename
|
||||||
|
local
|
||||||
|
param: HTTP_CLIENT_REQUEST_FILE_PARAMETER
|
||||||
|
do
|
||||||
|
create param.make_with_path (k, create {PATH}.make_from_string (a_location))
|
||||||
|
param.set_content_type (a_content_type)
|
||||||
|
form_parameters.force (param)
|
||||||
end
|
end
|
||||||
|
|
||||||
set_credentials_required (b: BOOLEAN)
|
set_credentials_required (b: BOOLEAN)
|
||||||
@@ -164,7 +176,8 @@ feature -- Element change
|
|||||||
-- Set `upload_data' to `a_data'
|
-- Set `upload_data' to `a_data'
|
||||||
--| note: the Current context can have upload_data XOR upload_filename, but not both.
|
--| note: the Current context can have upload_data XOR upload_filename, but not both.
|
||||||
require
|
require
|
||||||
has_upload_filename: (a_data /= Void and then not a_data.is_empty) implies not has_upload_filename
|
has_no_upload_filename: (a_data /= Void and then not a_data.is_empty) implies not has_upload_filename
|
||||||
|
has_no_form_data: (a_data /= Void and then not a_data.is_empty) implies not has_form_data
|
||||||
do
|
do
|
||||||
if a_data = Void or else a_data.is_empty then
|
if a_data = Void or else a_data.is_empty then
|
||||||
upload_data := Void
|
upload_data := Void
|
||||||
@@ -180,6 +193,7 @@ feature -- Element change
|
|||||||
--| note: the Current context can have upload_data XOR upload_filename, but not both.
|
--| note: the Current context can have upload_data XOR upload_filename, but not both.
|
||||||
require
|
require
|
||||||
has_no_upload_data: (a_fn /= Void and then not a_fn.is_empty) implies not has_upload_data
|
has_no_upload_data: (a_fn /= Void and then not a_fn.is_empty) implies not has_upload_data
|
||||||
|
has_no_form_data: (a_fn /= Void and then not a_fn.is_empty) implies not has_form_data
|
||||||
do
|
do
|
||||||
if a_fn = Void or else a_fn.is_empty then
|
if a_fn = Void or else a_fn.is_empty then
|
||||||
upload_filename := Void
|
upload_filename := Void
|
||||||
@@ -266,9 +280,9 @@ feature -- URL helpers
|
|||||||
a_url.append_character ('&')
|
a_url.append_character ('&')
|
||||||
end
|
end
|
||||||
l_first_param := False
|
l_first_param := False
|
||||||
uri_percent_encoder.append_query_name_encoded_string_to (ic.key, a_url)
|
uri_percent_encoder.append_query_name_encoded_string_to (ic.item.name, a_url)
|
||||||
a_url.append_character ('=')
|
a_url.append_character ('=')
|
||||||
uri_percent_encoder.append_query_value_encoded_string_to (ic.item, a_url)
|
ic.item.append_query_value_encoded_to (a_url)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -315,38 +329,35 @@ feature {NONE} -- Implementation
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
parameters_to_uri_percent_encoded_string (ht: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_32]): STRING_8
|
parameters_to_uri_percent_encoded_string (a_params: HTTP_CLIENT_REQUEST_PARAMETERS [HTTP_CLIENT_REQUEST_PARAMETER]): STRING_8
|
||||||
-- Build query urlencoded string using parameters from `ht'.
|
-- Build query urlencoded string using parameters from `a_params'.
|
||||||
do
|
do
|
||||||
create Result.make (64)
|
create Result.make (64)
|
||||||
across
|
across
|
||||||
ht as ic
|
a_params as ic
|
||||||
loop
|
loop
|
||||||
if not Result.is_empty then
|
if not Result.is_empty then
|
||||||
Result.append_character ('&')
|
Result.append_character ('&')
|
||||||
end
|
end
|
||||||
uri_percent_encoder.append_query_name_encoded_string_to (ic.key, Result)
|
uri_percent_encoder.append_query_name_encoded_string_to (ic.item.name, Result)
|
||||||
Result.append_character ('=')
|
Result.append_character ('=')
|
||||||
uri_percent_encoder.append_query_value_encoded_string_to (ic.item, Result)
|
ic.item.append_query_value_encoded_to (Result)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
parameters_to_x_www_form_urlencoded_string (ht: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_32]): STRING_8
|
parameters_to_x_www_form_urlencoded_string (a_params: HTTP_CLIENT_REQUEST_PARAMETERS [HTTP_CLIENT_REQUEST_PARAMETER]): STRING_8
|
||||||
-- Build x-www-form-urlencoded string using parameters from `ht'.
|
-- Build x-www-form-urlencoded string using parameters from `a_params'.
|
||||||
do
|
do
|
||||||
create Result.make (64)
|
create Result.make (64)
|
||||||
from
|
across
|
||||||
ht.start
|
a_params as ic
|
||||||
until
|
|
||||||
ht.after
|
|
||||||
loop
|
loop
|
||||||
if not Result.is_empty then
|
if not Result.is_empty then
|
||||||
Result.append_character ('&')
|
Result.append_character ('&')
|
||||||
end
|
end
|
||||||
Result.append (x_www_form_url_encoder.encoded_string (ht.key_for_iteration))
|
x_www_form_url_encoder.append_percent_encoded_string_to (ic.item.name, Result)
|
||||||
Result.append_character ('=')
|
Result.append_character ('=')
|
||||||
Result.append (x_www_form_url_encoder.encoded_string (ht.item_for_iteration))
|
ic.item.append_form_url_encoded_to (Result)
|
||||||
ht.forth
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {HTTP_CLIENT_REQUEST_FORM_PARAMETERS}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
HTTP_CLIENT_REQUEST_FORM_PARAMETERS
|
||||||
|
|
||||||
|
inherit
|
||||||
|
HTTP_CLIENT_REQUEST_PARAMETERS [HTTP_CLIENT_REQUEST_PARAMETER]
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
has_file_parameter: BOOLEAN
|
||||||
|
-- Has any file parameter?
|
||||||
|
do
|
||||||
|
Result := across items as ic some attached {HTTP_CLIENT_REQUEST_FILE_PARAMETER} ic.item end
|
||||||
|
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)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {HTTP_CLIENT_REQUEST_PARAMETER}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
HTTP_CLIENT_REQUEST_PARAMETER
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
name: READABLE_STRING_32
|
||||||
|
|
||||||
|
content_type: detachable READABLE_STRING_8
|
||||||
|
|
||||||
|
count: INTEGER
|
||||||
|
-- Integer representing the length of source value.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Conversion
|
||||||
|
|
||||||
|
append_form_url_encoded_to (a_output: STRING_8)
|
||||||
|
-- Append as form url encoded string to `a_output`.
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
append_query_value_encoded_to (a_output: STRING_8)
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
append_as_mime_encoded_to (a_output: STRING_8)
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Element change
|
||||||
|
|
||||||
|
set_name (a_name: READABLE_STRING_GENERAL)
|
||||||
|
do
|
||||||
|
name := a_name.as_string_32
|
||||||
|
end
|
||||||
|
|
||||||
|
set_content_type (ct: detachable READABLE_STRING_8)
|
||||||
|
do
|
||||||
|
content_type := ct
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
x_www_form_url_encoder: X_WWW_FORM_URL_ENCODER
|
||||||
|
-- Shared x-www-form-urlencoded encoder.
|
||||||
|
once
|
||||||
|
create Result
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_percent_encoder: URI_PERCENT_ENCODER
|
||||||
|
once
|
||||||
|
create Result
|
||||||
|
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)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {HTTP_CLIENT_REQUEST_PARAMETERS}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
HTTP_CLIENT_REQUEST_PARAMETERS [G -> HTTP_CLIENT_REQUEST_PARAMETER]
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ITERABLE [G]
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (nb: INTEGER)
|
||||||
|
do
|
||||||
|
create items.make (nb)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
is_empty: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := items.is_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
count: INTEGER
|
||||||
|
do
|
||||||
|
Result := items.count
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Element change
|
||||||
|
|
||||||
|
extend, force (i: G)
|
||||||
|
do
|
||||||
|
items.force (i)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Iteration
|
||||||
|
|
||||||
|
new_cursor: ARRAYED_LIST_ITERATION_CURSOR [G]
|
||||||
|
-- <Precursor>
|
||||||
|
do
|
||||||
|
Result := items.new_cursor
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
items: ARRAYED_LIST [G]
|
||||||
|
|
||||||
|
invariant
|
||||||
|
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)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {HTTP_CLIENT_REQUEST_QUERY_PARAMETERS}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
HTTP_CLIENT_REQUEST_QUERY_PARAMETERS
|
||||||
|
|
||||||
|
inherit
|
||||||
|
HTTP_CLIENT_REQUEST_PARAMETERS [HTTP_CLIENT_REQUEST_STRING_PARAMETER]
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
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)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {HTTP_CLIENT_REQUEST_FILE_PARAMETER}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
HTTP_CLIENT_REQUEST_FILE_PARAMETER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
HTTP_CLIENT_REQUEST_PARAMETER
|
||||||
|
|
||||||
|
create
|
||||||
|
make_with_path
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make_with_path (a_name: READABLE_STRING_GENERAL; a_path: PATH)
|
||||||
|
do
|
||||||
|
set_name (a_name)
|
||||||
|
location := a_path
|
||||||
|
if attached a_path.entry as e then
|
||||||
|
file_name := e.name
|
||||||
|
end
|
||||||
|
set_content_type ("application/octet-stream") -- Default
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
count: INTEGER
|
||||||
|
local
|
||||||
|
f: RAW_FILE
|
||||||
|
do
|
||||||
|
create f.make_with_path (location)
|
||||||
|
if f.exists and then f.is_access_readable then
|
||||||
|
Result := f.count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
location: PATH
|
||||||
|
|
||||||
|
file_name: detachable READABLE_STRING_32
|
||||||
|
|
||||||
|
feature -- Element change
|
||||||
|
|
||||||
|
set_file_name (fn: detachable READABLE_STRING_GENERAL)
|
||||||
|
do
|
||||||
|
if fn = Void then
|
||||||
|
file_name := Void
|
||||||
|
else
|
||||||
|
file_name := fn.to_string_32
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
exists: BOOLEAN
|
||||||
|
local
|
||||||
|
fut: FILE_UTILITIES
|
||||||
|
do
|
||||||
|
Result := fut.file_path_exists (location)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Data
|
||||||
|
|
||||||
|
file_content: detachable STRING_8
|
||||||
|
require
|
||||||
|
exists: exists
|
||||||
|
local
|
||||||
|
f: RAW_FILE
|
||||||
|
do
|
||||||
|
create f.make_with_path (location)
|
||||||
|
if f.exists and then f.is_access_readable then
|
||||||
|
create Result.make (f.count)
|
||||||
|
f.open_read
|
||||||
|
from
|
||||||
|
until
|
||||||
|
f.exhausted or f.end_of_file
|
||||||
|
loop
|
||||||
|
f.read_stream_thread_aware (2_048)
|
||||||
|
Result.append (f.last_string)
|
||||||
|
end
|
||||||
|
f.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Data
|
||||||
|
|
||||||
|
append_file_content_to (a_output: STRING)
|
||||||
|
-- Append content of file located at `location`to `a_output'.
|
||||||
|
require
|
||||||
|
exists: exists
|
||||||
|
local
|
||||||
|
f: RAW_FILE
|
||||||
|
l_buffer_size: INTEGER
|
||||||
|
do
|
||||||
|
create f.make_with_path (location)
|
||||||
|
if f.exists and then f.is_access_readable then
|
||||||
|
f.open_read
|
||||||
|
from
|
||||||
|
l_buffer_size := 2_048
|
||||||
|
until
|
||||||
|
f.exhausted or f.end_of_file
|
||||||
|
loop
|
||||||
|
f.read_stream_thread_aware (l_buffer_size)
|
||||||
|
a_output.append (f.last_string)
|
||||||
|
end
|
||||||
|
f.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Conversion
|
||||||
|
|
||||||
|
append_form_url_encoded_to (a_output: STRING_8)
|
||||||
|
-- Append as form url encoded string to `a_output`.
|
||||||
|
do
|
||||||
|
if exists and then attached file_content as s then
|
||||||
|
x_www_form_url_encoder.append_percent_encoded_string_to (s, a_output)
|
||||||
|
else
|
||||||
|
check exists: False end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
append_query_value_encoded_to (a_output: STRING_8)
|
||||||
|
do
|
||||||
|
if exists and then attached file_content as s then
|
||||||
|
uri_percent_encoder.append_query_value_encoded_string_to (s, a_output)
|
||||||
|
else
|
||||||
|
check exists: False end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
append_as_mime_encoded_to (a_output: STRING_8)
|
||||||
|
-- Encoded unicode string for mime value.
|
||||||
|
-- For instance uploaded filename, or form data key or values.
|
||||||
|
do
|
||||||
|
-- FIXME: find the proper encoding!
|
||||||
|
if exists then
|
||||||
|
append_file_content_to (a_output)
|
||||||
|
else
|
||||||
|
check exists: False end
|
||||||
|
end
|
||||||
|
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)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {HTTP_CLIENT_REQUEST_STRING_PARAMETER}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
HTTP_CLIENT_REQUEST_STRING_PARAMETER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
HTTP_CLIENT_REQUEST_PARAMETER
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_name, a_value: READABLE_STRING_GENERAL)
|
||||||
|
do
|
||||||
|
set_name (a_name)
|
||||||
|
value := a_value.as_string_32
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
value: READABLE_STRING_32
|
||||||
|
|
||||||
|
count: INTEGER
|
||||||
|
do
|
||||||
|
Result := value.count
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Conversion
|
||||||
|
|
||||||
|
append_form_url_encoded_to (a_output: STRING_8)
|
||||||
|
-- Append as form url encoded string to `a_output`.
|
||||||
|
do
|
||||||
|
x_www_form_url_encoder.append_percent_encoded_string_to (value, a_output)
|
||||||
|
end
|
||||||
|
|
||||||
|
append_query_value_encoded_to (a_output: STRING_8)
|
||||||
|
do
|
||||||
|
uri_percent_encoder.append_query_value_encoded_string_to (value, a_output)
|
||||||
|
end
|
||||||
|
|
||||||
|
append_as_mime_encoded_to (a_output: STRING_8)
|
||||||
|
-- Encoded unicode string for mime value.
|
||||||
|
-- For instance uploaded filename, or form data key or values.
|
||||||
|
local
|
||||||
|
utf: UTF_CONVERTER
|
||||||
|
do
|
||||||
|
-- FIXME: find the proper encoding!
|
||||||
|
utf.utf_32_string_into_utf_8_string_8 (value, a_output)
|
||||||
|
end
|
||||||
|
|
||||||
|
invariant
|
||||||
|
|
||||||
|
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)"
|
||||||
|
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
|
||||||
@@ -58,7 +58,6 @@ feature -- Execution
|
|||||||
ctx: like context
|
ctx: like context
|
||||||
p_slist: POINTER
|
p_slist: POINTER
|
||||||
retried: BOOLEAN
|
retried: BOOLEAN
|
||||||
l_form_data: detachable HASH_TABLE [READABLE_STRING_32, READABLE_STRING_32]
|
|
||||||
l_upload_data: detachable READABLE_STRING_8
|
l_upload_data: detachable READABLE_STRING_8
|
||||||
l_upload_filename: detachable READABLE_STRING_GENERAL
|
l_upload_filename: detachable READABLE_STRING_GENERAL
|
||||||
l_headers: like headers
|
l_headers: like headers
|
||||||
@@ -151,70 +150,19 @@ feature -- Execution
|
|||||||
--| Credentials not provided ...
|
--| Credentials not provided ...
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if ctx.has_upload_data then
|
if ctx.has_upload_data then
|
||||||
l_upload_data := ctx.upload_data
|
l_upload_data := ctx.upload_data
|
||||||
end
|
end
|
||||||
if ctx.has_upload_filename then
|
if ctx.has_upload_filename then
|
||||||
l_upload_filename := ctx.upload_filename
|
l_upload_filename := ctx.upload_filename
|
||||||
end
|
end
|
||||||
if ctx.has_form_data then
|
|
||||||
l_form_data := ctx.form_parameters
|
|
||||||
check non_empty_form_data: not l_form_data.is_empty end
|
|
||||||
if l_upload_data = Void and l_upload_filename = Void then
|
|
||||||
-- Send as form-urlencoded
|
|
||||||
if
|
|
||||||
attached l_headers.item ("Content-Type") as l_ct
|
|
||||||
then
|
|
||||||
if l_ct.starts_with ("application/x-www-form-urlencoded") then
|
|
||||||
-- Content-Type is already application/x-www-form-urlencoded
|
|
||||||
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
|
||||||
elseif l_ct.starts_with ("multipart/form-data") then
|
|
||||||
l_use_curl_form := True
|
|
||||||
else
|
|
||||||
-- Not supported, use libcurl form.
|
|
||||||
l_use_curl_form := True
|
|
||||||
end
|
|
||||||
else
|
|
||||||
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
|
||||||
end
|
|
||||||
else
|
|
||||||
l_use_curl_form := True
|
|
||||||
end
|
|
||||||
if l_use_curl_form then
|
|
||||||
create l_form.make
|
|
||||||
create l_last.make
|
|
||||||
from
|
|
||||||
l_form_data.start
|
|
||||||
until
|
|
||||||
l_form_data.after
|
|
||||||
loop
|
|
||||||
curl.formadd_string_string (l_form, l_last,
|
|
||||||
{CURL_FORM_CONSTANTS}.curlform_copyname, l_form_data.key_for_iteration,
|
|
||||||
{CURL_FORM_CONSTANTS}.curlform_copycontents, l_form_data.item_for_iteration,
|
|
||||||
{CURL_FORM_CONSTANTS}.curlform_end
|
|
||||||
)
|
|
||||||
l_form_data.forth
|
|
||||||
end
|
|
||||||
if l_upload_filename /= Void then
|
|
||||||
curl.formadd_string_string (l_form, l_last,
|
|
||||||
{CURL_FORM_CONSTANTS}.curlform_copyname, "file",
|
|
||||||
{CURL_FORM_CONSTANTS}.curlform_file, l_upload_filename,
|
|
||||||
{CURL_FORM_CONSTANTS}.curlform_end
|
|
||||||
)
|
|
||||||
l_upload_filename := Void
|
|
||||||
end
|
|
||||||
l_last.release_item
|
|
||||||
curl_easy.setopt_form (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httppost, l_form)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if l_upload_data /= Void then
|
if l_upload_data /= Void then
|
||||||
check
|
check
|
||||||
post_or_put_request_method: request_method.is_case_insensitive_equal ("POST")
|
post_or_put_request_method: request_method.is_case_insensitive_equal ("POST")
|
||||||
or request_method.is_case_insensitive_equal ("PUT")
|
or request_method.is_case_insensitive_equal ("PUT")
|
||||||
or request_method.is_case_insensitive_equal ("PATCH")
|
or request_method.is_case_insensitive_equal ("PATCH")
|
||||||
end
|
end
|
||||||
|
check no_form_data: not ctx.has_form_data end
|
||||||
|
|
||||||
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_postfields, l_upload_data)
|
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)
|
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_postfieldsize, l_upload_data.count)
|
||||||
@@ -224,6 +172,7 @@ feature -- Execution
|
|||||||
or request_method.is_case_insensitive_equal ("PUT")
|
or request_method.is_case_insensitive_equal ("PUT")
|
||||||
or request_method.is_case_insensitive_equal ("PATCH")
|
or request_method.is_case_insensitive_equal ("PATCH")
|
||||||
end
|
end
|
||||||
|
check no_form_data: not ctx.has_form_data end
|
||||||
|
|
||||||
create l_upload_file.make_with_name (l_upload_filename)
|
create l_upload_file.make_with_name (l_upload_filename)
|
||||||
if l_upload_file.exists and then l_upload_file.is_readable then
|
if l_upload_file.exists and then l_upload_file.is_readable then
|
||||||
@@ -238,12 +187,59 @@ feature -- Execution
|
|||||||
l_upload_file.open_read
|
l_upload_file.open_read
|
||||||
curl_easy.set_curl_function (l_custom_function)
|
curl_easy.set_curl_function (l_custom_function)
|
||||||
end
|
end
|
||||||
|
elseif
|
||||||
|
ctx.has_form_data and
|
||||||
|
attached ctx.form_parameters as l_form_data
|
||||||
|
then
|
||||||
|
check non_empty_form_data: not l_form_data.is_empty end
|
||||||
|
-- Send as form-urlencoded
|
||||||
|
if
|
||||||
|
attached l_headers.item ("Content-Type") as l_ct
|
||||||
|
then
|
||||||
|
if l_ct.starts_with ("application/x-www-form-urlencoded") then
|
||||||
|
-- Content-Type is already application/x-www-form-urlencoded
|
||||||
|
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
||||||
|
elseif l_ct.starts_with ("multipart/form-data") or l_form_data.has_file_parameter then
|
||||||
|
l_use_curl_form := True
|
||||||
|
else
|
||||||
|
-- Not supported, use libcurl form.
|
||||||
|
l_use_curl_form := True
|
||||||
|
end
|
||||||
|
else
|
||||||
|
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
||||||
|
end
|
||||||
|
if l_use_curl_form then
|
||||||
|
create l_form.make
|
||||||
|
create l_last.make
|
||||||
|
across
|
||||||
|
l_form_data as ic
|
||||||
|
loop
|
||||||
|
if attached {HTTP_CLIENT_REQUEST_STRING_PARAMETER} ic.item as strparam then
|
||||||
|
curl.formadd_string_string (l_form, l_last,
|
||||||
|
{CURL_FORM_CONSTANTS}.curlform_copyname, strparam.name,
|
||||||
|
{CURL_FORM_CONSTANTS}.curlform_copycontents, strparam.value,
|
||||||
|
{CURL_FORM_CONSTANTS}.curlform_end
|
||||||
|
)
|
||||||
|
elseif attached {HTTP_CLIENT_REQUEST_FILE_PARAMETER} ic.item as fileparam then
|
||||||
|
curl.formadd_string_string (l_form, l_last,
|
||||||
|
{CURL_FORM_CONSTANTS}.curlform_copyname, "file",
|
||||||
|
{CURL_FORM_CONSTANTS}.curlform_file, fileparam.location.name,
|
||||||
|
{CURL_FORM_CONSTANTS}.curlform_end
|
||||||
|
)
|
||||||
|
else
|
||||||
|
check supported_parameter_type: False end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
l_last.release_item
|
||||||
|
curl_easy.setopt_form (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httppost, l_form)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
check no_upload_data: l_upload_data = Void and l_upload_filename = Void end
|
-- No form, or upload data to send!
|
||||||
|
check no_data: not (ctx.has_upload_data or ctx.has_upload_filename or ctx.has_form_data) end
|
||||||
end
|
end
|
||||||
end -- ctx /= Void
|
end -- ctx /= Void
|
||||||
|
|
||||||
--| Header
|
--| Header
|
||||||
across
|
across
|
||||||
l_headers as curs
|
l_headers as curs
|
||||||
loop
|
loop
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ feature -- Access
|
|||||||
l_authorization: HTTP_AUTHORIZATION
|
l_authorization: HTTP_AUTHORIZATION
|
||||||
l_platform: STRING
|
l_platform: STRING
|
||||||
l_upload_data: detachable READABLE_STRING_8
|
l_upload_data: detachable READABLE_STRING_8
|
||||||
l_form_data: detachable HASH_TABLE [READABLE_STRING_32, READABLE_STRING_32]
|
|
||||||
ctx: like context
|
ctx: like context
|
||||||
|
l_ct: detachable READABLE_STRING_8
|
||||||
l_upload_file: detachable RAW_FILE
|
l_upload_file: detachable RAW_FILE
|
||||||
l_upload_filename: detachable READABLE_STRING_GENERAL
|
l_upload_filename: detachable READABLE_STRING_GENERAL
|
||||||
l_form_string: STRING
|
l_form_string: STRING
|
||||||
@@ -149,7 +149,7 @@ feature -- Access
|
|||||||
then
|
then
|
||||||
create l_authorization.make_basic_auth (u_name, u_pass)
|
create l_authorization.make_basic_auth (u_name, u_pass)
|
||||||
if attached l_authorization.http_authorization as auth then
|
if attached l_authorization.http_authorization as auth then
|
||||||
headers.extend (auth, "Authorization")
|
headers.force (auth, "Authorization")
|
||||||
end
|
end
|
||||||
check headers.has_key ("Authorization") end
|
check headers.has_key ("Authorization") end
|
||||||
end
|
end
|
||||||
@@ -176,7 +176,7 @@ feature -- Access
|
|||||||
else
|
else
|
||||||
l_platform := "Unknown"
|
l_platform := "Unknown"
|
||||||
end
|
end
|
||||||
headers.extend ("eiffelhttpclient/" + net_http_client_version + " (" + l_platform + ")", "User-Agent")
|
headers.force ("eiffelhttpclient/" + net_http_client_version + " (" + l_platform + ")", "User-Agent")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- handle sending data
|
-- handle sending data
|
||||||
@@ -191,67 +191,52 @@ feature -- Access
|
|||||||
l_upload_data := ctx.upload_data
|
l_upload_data := ctx.upload_data
|
||||||
end
|
end
|
||||||
|
|
||||||
if ctx.has_form_data then
|
if l_upload_data /= Void then
|
||||||
l_form_data := ctx.form_parameters
|
|
||||||
if l_upload_data = Void and l_upload_filename = Void then
|
|
||||||
if
|
|
||||||
attached headers.item ("Content-Type") as l_ct
|
|
||||||
then
|
|
||||||
if l_ct.starts_with ("application/x-www-form-urlencoded") then
|
|
||||||
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
|
||||||
elseif l_ct.starts_with ("multipart/form-data") then
|
|
||||||
-- create form using multipart/form-data encoding
|
|
||||||
l_boundary := new_mime_boundary (l_form_data)
|
|
||||||
headers.extend ("multipart/form-data; boundary=" + l_boundary, "Content-Type")
|
|
||||||
l_upload_data := form_date_and_uploaded_files_to_mime_string (l_form_data, l_upload_filename, l_boundary)
|
|
||||||
else
|
|
||||||
-- not supported !
|
|
||||||
-- Send as form-urlencoded
|
|
||||||
headers.extend ("application/x-www-form-urlencoded", "Content-Type")
|
|
||||||
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- Send as form-urlencoded
|
|
||||||
headers.extend ("application/x-www-form-urlencoded", "Content-Type")
|
|
||||||
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
|
||||||
end
|
|
||||||
headers.extend (l_upload_data.count.out, "Content-Length")
|
|
||||||
if l_is_chunked_transfer_encoding then
|
|
||||||
-- Discard chunked transfer encoding
|
|
||||||
headers.remove ("Transfer-Encoding")
|
|
||||||
l_is_chunked_transfer_encoding := False
|
|
||||||
end
|
|
||||||
elseif l_form_data /= Void then
|
|
||||||
check l_upload_data = Void end
|
|
||||||
|
|
||||||
-- create form using multipart/form-data encoding
|
|
||||||
l_boundary := new_mime_boundary (l_form_data)
|
|
||||||
headers.extend ("multipart/form-data; boundary=" + l_boundary, "Content-Type")
|
|
||||||
l_upload_data := form_date_and_uploaded_files_to_mime_string (l_form_data, l_upload_filename, l_boundary)
|
|
||||||
headers.extend (l_upload_data.count.out, "Content-Length")
|
|
||||||
if l_is_chunked_transfer_encoding then
|
|
||||||
-- Discard chunked transfer encoding
|
|
||||||
headers.remove ("Transfer-Encoding")
|
|
||||||
l_is_chunked_transfer_encoding := False
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif l_upload_data /= Void then
|
|
||||||
check ctx.has_upload_data end
|
check ctx.has_upload_data end
|
||||||
|
check no_form_data: not ctx.has_form_data end
|
||||||
if not headers.has ("Content-Type") then
|
if not headers.has ("Content-Type") then
|
||||||
headers.extend ("application/x-www-form-urlencoded", "Content-Type")
|
headers.force ("application/x-www-form-urlencoded", "Content-Type")
|
||||||
end
|
end
|
||||||
if not l_is_chunked_transfer_encoding then
|
if not l_is_chunked_transfer_encoding then
|
||||||
headers.extend (l_upload_data.count.out, "Content-Length")
|
headers.force (l_upload_data.count.out, "Content-Length")
|
||||||
end
|
end
|
||||||
elseif l_upload_filename /= Void then
|
elseif l_upload_filename /= Void then
|
||||||
check ctx.has_upload_filename end
|
check ctx.has_upload_filename end
|
||||||
|
check no_form_data: not ctx.has_form_data end
|
||||||
create l_upload_file.make_with_name (l_upload_filename)
|
create l_upload_file.make_with_name (l_upload_filename)
|
||||||
if l_upload_file.exists and then l_upload_file.is_access_readable then
|
if l_upload_file.exists and then l_upload_file.is_access_readable then
|
||||||
if not l_is_chunked_transfer_encoding then
|
if not l_is_chunked_transfer_encoding then
|
||||||
headers.extend (l_upload_file.count.out, "Content-Length")
|
headers.force (l_upload_file.count.out, "Content-Length")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
check l_upload_file /= Void end
|
check l_upload_file /= Void end
|
||||||
|
elseif
|
||||||
|
ctx.has_form_data and
|
||||||
|
attached ctx.form_parameters as l_form_data
|
||||||
|
then
|
||||||
|
l_ct := headers.item ("Content-Type")
|
||||||
|
if l_ct /= Void and then l_ct.starts_with ("application/x-www-form-urlencoded") then
|
||||||
|
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
||||||
|
elseif
|
||||||
|
(l_ct /= Void and then l_ct.starts_with ("multipart/form-data"))
|
||||||
|
or l_form_data.has_file_parameter
|
||||||
|
then
|
||||||
|
-- create form using multipart/form-data encoding
|
||||||
|
l_boundary := new_mime_boundary (l_form_data)
|
||||||
|
headers.force ("multipart/form-data; boundary=" + l_boundary, "Content-Type")
|
||||||
|
l_upload_data := form_date_and_uploaded_files_to_mime_string (l_form_data, l_boundary)
|
||||||
|
else
|
||||||
|
-- not supported !
|
||||||
|
-- Send as form-urlencoded
|
||||||
|
headers.force ("application/x-www-form-urlencoded", "Content-Type")
|
||||||
|
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
||||||
|
end
|
||||||
|
headers.force (l_upload_data.count.out, "Content-Length")
|
||||||
|
if l_is_chunked_transfer_encoding then
|
||||||
|
-- Discard chunked transfer encoding
|
||||||
|
headers.remove ("Transfer-Encoding")
|
||||||
|
l_is_chunked_transfer_encoding := False
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -482,14 +467,9 @@ feature {NONE} -- Helpers
|
|||||||
Result := a_status >= 300 and a_status < 400
|
Result := a_status >= 300 and a_status < 400
|
||||||
end
|
end
|
||||||
|
|
||||||
form_date_and_uploaded_files_to_mime_string (a_form_parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_32]; a_upload_filename: detachable READABLE_STRING_GENERAL; a_mime_boundary: READABLE_STRING_8): STRING
|
form_date_and_uploaded_files_to_mime_string (a_form_parameters: ITERABLE [HTTP_CLIENT_REQUEST_PARAMETER]; a_mime_boundary: READABLE_STRING_8): STRING
|
||||||
-- Form data and uploaded files converted to mime string.
|
-- Form data and uploaded files converted to mime string.
|
||||||
-- TODO: design a proper MIME... component.
|
-- TODO: design a proper MIME... component.
|
||||||
local
|
|
||||||
l_path: PATH
|
|
||||||
l_mime_type: READABLE_STRING_8
|
|
||||||
l_upload_file: detachable RAW_FILE
|
|
||||||
l_mime_type_mapping: HTTP_FILE_EXTENSION_MIME_MAPPING
|
|
||||||
do
|
do
|
||||||
create Result.make (100)
|
create Result.make (100)
|
||||||
across
|
across
|
||||||
@@ -500,48 +480,26 @@ feature {NONE} -- Helpers
|
|||||||
Result.append (http_end_of_header_line)
|
Result.append (http_end_of_header_line)
|
||||||
Result.append ("Content-Disposition: form-data; name=")
|
Result.append ("Content-Disposition: form-data; name=")
|
||||||
Result.append_character ('%"')
|
Result.append_character ('%"')
|
||||||
Result.append (string_to_mime_encoded_string (ic.key))
|
Result.append (string_to_mime_encoded_string (ic.item.name))
|
||||||
Result.append_character ('%"')
|
Result.append_character ('%"')
|
||||||
Result.append (http_end_of_header_line)
|
|
||||||
Result.append (http_end_of_header_line)
|
|
||||||
Result.append (string_to_mime_encoded_string (ic.item))
|
|
||||||
Result.append (http_end_of_header_line)
|
|
||||||
end
|
|
||||||
|
|
||||||
if a_upload_filename /= Void then
|
|
||||||
-- get file extension, otherwise set default
|
|
||||||
create l_mime_type_mapping.make_default
|
|
||||||
create l_path.make_from_string (a_upload_filename)
|
|
||||||
if
|
if
|
||||||
attached l_path.extension as ext and then
|
attached {HTTP_CLIENT_REQUEST_FILE_PARAMETER} ic.item as fileparam and then
|
||||||
attached l_mime_type_mapping.mime_type (ext) as l_mt
|
attached fileparam.file_name as fn
|
||||||
then
|
then
|
||||||
l_mime_type := l_mt
|
Result.append ("; filename=")
|
||||||
else
|
Result.append_character ('%"')
|
||||||
l_mime_type := "application/octet-stream"
|
Result.append (string_to_mime_encoded_string (fn))
|
||||||
|
Result.append_character ('%"')
|
||||||
end
|
end
|
||||||
Result.append ("--")
|
if attached ic.item.content_type as ct then
|
||||||
Result.append (a_mime_boundary)
|
Result.append (http_end_of_header_line)
|
||||||
Result.append (http_end_of_header_line)
|
Result.append ("Content-Type: ")
|
||||||
Result.append ("Content-Disposition: form-data; name=%"")
|
Result.append (ct)
|
||||||
Result.append (string_to_mime_encoded_string (a_upload_filename))
|
|
||||||
Result.append_character ('%"')
|
|
||||||
Result.append ("; filename=%"")
|
|
||||||
Result.append (string_to_mime_encoded_string (a_upload_filename))
|
|
||||||
Result.append_character ('%"')
|
|
||||||
Result.append (http_end_of_header_line)
|
|
||||||
Result.append ("Content-Type: ")
|
|
||||||
Result.append (l_mime_type)
|
|
||||||
Result.append (http_end_of_header_line)
|
|
||||||
Result.append (http_end_of_header_line)
|
|
||||||
|
|
||||||
create l_upload_file.make_with_path (l_path)
|
|
||||||
if l_upload_file.exists and then l_upload_file.is_access_readable then
|
|
||||||
append_file_content_to (l_upload_file, l_upload_file.count, Result)
|
|
||||||
-- Reset l_upload_file to Void, since the related content is already processed.
|
|
||||||
l_upload_file := Void
|
|
||||||
end
|
end
|
||||||
Result.append (http_end_of_header_line)
|
Result.append (http_end_of_header_line)
|
||||||
|
Result.append (http_end_of_header_line)
|
||||||
|
ic.item.append_as_mime_encoded_to (Result)
|
||||||
|
Result.append (http_end_of_header_line)
|
||||||
end
|
end
|
||||||
Result.append ("--")
|
Result.append ("--")
|
||||||
Result.append (a_mime_boundary)
|
Result.append (a_mime_boundary)
|
||||||
@@ -893,7 +851,7 @@ feature {NONE} -- Helpers
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
new_mime_boundary (a_data: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_32]): STRING
|
new_mime_boundary (a_data: ITERABLE [HTTP_CLIENT_REQUEST_PARAMETER]): STRING
|
||||||
-- New MIME boundary.
|
-- New MIME boundary.
|
||||||
local
|
local
|
||||||
s: STRING
|
s: STRING
|
||||||
@@ -904,7 +862,7 @@ feature {NONE} -- Helpers
|
|||||||
across
|
across
|
||||||
a_data as ic
|
a_data as ic
|
||||||
loop
|
loop
|
||||||
i := i + ic.item.count + ic.key.count
|
i := i + ic.item.count + ic.item.name.count
|
||||||
end
|
end
|
||||||
create ran.set_seed (i) -- FIXME: use a real random seed.
|
create ran.set_seed (i) -- FIXME: use a real random seed.
|
||||||
ran.start
|
ran.start
|
||||||
|
|||||||
+4
-3
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="test_http_client" uuid="920E5C50-41E1-4DAC-8D48-D9C860E49228">
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="testing_http_client" uuid="920E5C50-41E1-4DAC-8D48-D9C860E49228">
|
||||||
<target name="test_http_client">
|
<target name="testing_http_client">
|
||||||
<root class="TEST" feature="make"/>
|
<root class="TEST" feature="make"/>
|
||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>/.git$</exclude>
|
<exclude>/.git$</exclude>
|
||||||
@@ -10,7 +10,8 @@
|
|||||||
<option warning="true" void_safety="all">
|
<option warning="true" void_safety="all">
|
||||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
</option>
|
</option>
|
||||||
<variable name="netssl_http_client_enabled" value="false"/>
|
<variable name="ssl_enabled" value="true"/>
|
||||||
|
<variable name="netssl_http_client_enabled" value="true"/>
|
||||||
<variable name="net_http_client_disabled" value="false"/>
|
<variable name="net_http_client_disabled" value="false"/>
|
||||||
<variable name="libcurl_http_client_disabled" value="false"/>
|
<variable name="libcurl_http_client_disabled" value="false"/>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
@@ -59,6 +59,11 @@ feature -- Tests
|
|||||||
test_post_with_file_and_form_data
|
test_post_with_file_and_form_data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
libcurl_test_post_with_multiple_file_and_form_data
|
||||||
|
do
|
||||||
|
test_post_with_multiple_file_and_form_data
|
||||||
|
end
|
||||||
|
|
||||||
libcurl_test_get_with_redirection
|
libcurl_test_get_with_redirection
|
||||||
do
|
do
|
||||||
test_get_with_redirection
|
test_get_with_redirection
|
||||||
|
|||||||
@@ -59,6 +59,11 @@ feature -- Tests
|
|||||||
test_post_with_file_and_form_data
|
test_post_with_file_and_form_data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
net_test_post_with_multiple_file_and_form_data
|
||||||
|
do
|
||||||
|
test_post_with_multiple_file_and_form_data
|
||||||
|
end
|
||||||
|
|
||||||
net_test_get_with_redirection
|
net_test_get_with_redirection
|
||||||
do
|
do
|
||||||
test_get_with_redirection
|
test_get_with_redirection
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ feature -- Initialization
|
|||||||
on_prepare
|
on_prepare
|
||||||
do
|
do
|
||||||
Precursor
|
Precursor
|
||||||
global_requestbin_path := "/s0jkhhs0"
|
if is_using_requestbin and global_requestbin_path = Void then
|
||||||
if global_requestbin_path = Void then
|
|
||||||
global_requestbin_path := new_requestbin_path
|
global_requestbin_path := new_requestbin_path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -35,6 +34,12 @@ feature -- Factory
|
|||||||
|
|
||||||
feature -- Requestbin
|
feature -- Requestbin
|
||||||
|
|
||||||
|
is_using_requestbin: BOOLEAN = False
|
||||||
|
is_using_mockbincom: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := not is_using_requestbin
|
||||||
|
end
|
||||||
|
|
||||||
global_requestbin_path: detachable READABLE_STRING_8
|
global_requestbin_path: detachable READABLE_STRING_8
|
||||||
|
|
||||||
new_requestbin_path: detachable STRING
|
new_requestbin_path: detachable STRING
|
||||||
@@ -42,7 +47,7 @@ feature -- Requestbin
|
|||||||
i,j: INTEGER
|
i,j: INTEGER
|
||||||
do
|
do
|
||||||
if
|
if
|
||||||
attached new_session ("http://requestb.in") as sess and then
|
attached new_session ("https://requestb.in") as sess and then
|
||||||
attached sess.post ("/api/v1/bins", Void, Void) as resp
|
attached sess.post ("/api/v1/bins", Void, Void) as resp
|
||||||
then
|
then
|
||||||
if resp.error_occurred then
|
if resp.error_occurred then
|
||||||
@@ -67,13 +72,30 @@ feature -- Requestbin
|
|||||||
if not Result.starts_with ("/") then
|
if not Result.starts_with ("/") then
|
||||||
Result.prepend_character ('/')
|
Result.prepend_character ('/')
|
||||||
end
|
end
|
||||||
print ("new_requestbin_path => http://requestb.in" + Result + "?inspect%N")
|
print ("new_requestbin_path => " + sess.base_url + Result + "?inspect%N")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
new_web_session: like new_session
|
||||||
|
do
|
||||||
|
if is_using_mockbincom then
|
||||||
|
Result := new_session ("http://mockbin.com/request")
|
||||||
|
end
|
||||||
|
if Result = Void and is_using_requestbin then
|
||||||
|
if attached global_requestbin_path as l_path then
|
||||||
|
Result := new_session ("https://requestb.in" + l_path)
|
||||||
|
else
|
||||||
|
assert ("Has requestbin path", False)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if Result = Void then
|
||||||
|
Result := new_session ("http://mockbin.com/request") -- Default
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Factory
|
feature -- Factory
|
||||||
|
|
||||||
test_post_url_encoded
|
test_post_url_encoded
|
||||||
@@ -81,288 +103,200 @@ feature -- Factory
|
|||||||
sess: HTTP_CLIENT_SESSION
|
sess: HTTP_CLIENT_SESSION
|
||||||
h: STRING_8
|
h: STRING_8
|
||||||
do
|
do
|
||||||
if attached global_requestbin_path as requestbin_path then
|
-- URL ENCODED POST REQUEST
|
||||||
-- URL ENCODED POST REQUEST
|
-- check requestbin to ensure the "Hello World" has been received in the raw body
|
||||||
-- check requestbin to ensure the "Hello World" has been received in the raw body
|
-- also check that User-Agent was sent
|
||||||
-- also check that User-Agent was sent
|
create h.make_empty
|
||||||
create h.make_empty
|
sess := new_web_session
|
||||||
sess := new_session ("http://requestb.in")
|
if
|
||||||
if
|
attached sess.post ("", Void, "Hello World") as res
|
||||||
attached sess.post (requestbin_path, Void, "Hello World") as res and then
|
then
|
||||||
attached res.headers as hds
|
check_response (res)
|
||||||
then
|
|
||||||
across
|
|
||||||
hds as c
|
|
||||||
loop
|
|
||||||
h.append (c.item.name + ": " + c.item.value + "%R%N")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print (h)
|
|
||||||
else
|
|
||||||
assert ("Has requestbin path", False)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test_post_with_form_data
|
test_post_with_form_data
|
||||||
local
|
local
|
||||||
sess: HTTP_CLIENT_SESSION
|
sess: HTTP_CLIENT_SESSION
|
||||||
h: STRING_8
|
|
||||||
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||||
do
|
do
|
||||||
if attached global_requestbin_path as requestbin_path then
|
-- POST REQUEST WITH FORM DATA
|
||||||
|
-- check requestbin to ensure the form parameters are correctly received
|
||||||
-- POST REQUEST WITH FORM DATA
|
sess := new_web_session
|
||||||
-- check requestbin to ensure the form parameters are correctly received
|
create l_ctx.make
|
||||||
sess := new_session ("http://requestb.in")
|
l_ctx.add_form_parameter ("First Key", "First Value")
|
||||||
create l_ctx.make
|
l_ctx.add_form_parameter ("Second Key", "Second Value")
|
||||||
l_ctx.add_form_parameter ("First Key", "First Value")
|
l_ctx.add_form_parameter ("unicode", {STRING_32} "Hello / 你好 !")
|
||||||
l_ctx.add_form_parameter ("Second Key", "Second Value")
|
l_ctx.add_form_parameter ({STRING_32} "Field 你好 !", "How are you?")
|
||||||
l_ctx.add_form_parameter ("unicode", {STRING_32} "Hello / 你好 !")
|
if
|
||||||
l_ctx.add_form_parameter ({STRING_32} "Field 你好 !", "How are you?")
|
attached sess.post ("", l_ctx, "") as res
|
||||||
create h.make_empty
|
then
|
||||||
if
|
check_response (res)
|
||||||
attached sess.post (requestbin_path, l_ctx, "") as res and then
|
|
||||||
attached res.headers as hds
|
|
||||||
then
|
|
||||||
across
|
|
||||||
hds as c
|
|
||||||
loop
|
|
||||||
h.append (c.item.name + ": " + c.item.value + "%R%N")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print (h)
|
|
||||||
else
|
|
||||||
assert ("Has requestbin path", False)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test_post_with_uncommon_form_data
|
test_post_with_uncommon_form_data
|
||||||
local
|
local
|
||||||
sess: HTTP_CLIENT_SESSION
|
sess: HTTP_CLIENT_SESSION
|
||||||
h: STRING_8
|
|
||||||
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||||
do
|
do
|
||||||
if attached global_requestbin_path as requestbin_path then
|
-- POST REQUEST WITH FORM DATA
|
||||||
|
-- check requestbin to ensure the form parameters are correctly received
|
||||||
|
sess := new_web_session
|
||||||
|
create l_ctx.make
|
||||||
|
|
||||||
-- POST REQUEST WITH FORM DATA
|
l_ctx.add_form_parameter ("title", "Eiffel World!") -- space and !
|
||||||
-- check requestbin to ensure the form parameters are correctly received
|
l_ctx.add_form_parameter ("path", "foo/bar") -- slash
|
||||||
sess := new_session ("http://requestb.in")
|
l_ctx.add_form_parameter ("unreserved", ":!@[]{}()*") -- ...
|
||||||
create l_ctx.make
|
l_ctx.add_form_parameter ("reserved", "+=?&_#_") -- ...
|
||||||
|
l_ctx.add_form_parameter ("a=b", "a=b") -- equal sign
|
||||||
|
l_ctx.add_form_parameter ("test", "!$&'()*") --
|
||||||
|
l_ctx.add_form_parameter ("lst[a][b]", "[123][456]") -- brackets
|
||||||
|
l_ctx.add_form_parameter ("pos{1,2}", "loc{a,b}") -- curly brackets
|
||||||
|
l_ctx.add_form_parameter ("?foo", "?bar") -- question mark
|
||||||
|
l_ctx.add_form_parameter ("?", "?") -- question mark
|
||||||
|
l_ctx.add_form_parameter ("&bar", "&bar") -- ampersand
|
||||||
|
l_ctx.add_form_parameter ("&", "&") -- ampersand
|
||||||
|
|
||||||
l_ctx.add_form_parameter ("title", "Eiffel World!") -- space and !
|
assert ("form data well generated", l_ctx.form_parameters_to_x_www_form_url_encoded_string.same_string ("title=Eiffel+World!&path=foo%%2Fbar&unreserved=%%3A!%%40%%5B%%5D%%7B%%7D()*&reserved=%%2B%%3D%%3F%%26_%%23_&a%%3Db=a%%3Db&test=!%%24%%26'()*&lst%%5Ba%%5D%%5Bb%%5D=%%5B123%%5D%%5B456%%5D&pos%%7B1%%2C2%%7D=loc%%7Ba%%2Cb%%7D&%%3Ffoo=%%3Fbar&%%3F=%%3F&%%26bar=%%26bar&%%26=%%26"))
|
||||||
l_ctx.add_form_parameter ("path", "foo/bar") -- slash
|
|
||||||
l_ctx.add_form_parameter ("unreserved", ":!@[]{}()*") -- ...
|
|
||||||
l_ctx.add_form_parameter ("reserved", "+=?&_#_") -- ...
|
|
||||||
l_ctx.add_form_parameter ("a=b", "a=b") -- equal sign
|
|
||||||
l_ctx.add_form_parameter ("test", "!$&'()*") --
|
|
||||||
l_ctx.add_form_parameter ("lst[a][b]", "[123][456]") -- brackets
|
|
||||||
l_ctx.add_form_parameter ("pos{1,2}", "loc{a,b}") -- curly brackets
|
|
||||||
l_ctx.add_form_parameter ("?foo", "?bar") -- question mark
|
|
||||||
l_ctx.add_form_parameter ("?", "?") -- question mark
|
|
||||||
l_ctx.add_form_parameter ("&bar", "&bar") -- ampersand
|
|
||||||
l_ctx.add_form_parameter ("&", "&") -- ampersand
|
|
||||||
|
|
||||||
assert ("form data well generated", l_ctx.form_parameters_to_x_www_form_url_encoded_string.same_string ("title=Eiffel+World!&path=foo%%2Fbar&unreserved=%%3A!%%40%%5B%%5D%%7B%%7D()*&reserved=%%2B%%3D%%3F%%26_%%23_&a%%3Db=a%%3Db&test=!%%24%%26'()*&lst%%5Ba%%5D%%5Bb%%5D=%%5B123%%5D%%5B456%%5D&pos%%7B1%%2C2%%7D=loc%%7Ba%%2Cb%%7D&%%3Ffoo=%%3Fbar&%%3F=%%3F&%%26bar=%%26bar&%%26=%%26"))
|
if
|
||||||
|
attached sess.post ("", l_ctx, "") as res
|
||||||
create h.make_empty
|
then
|
||||||
if
|
check_response (res)
|
||||||
attached sess.post (requestbin_path, l_ctx, "") as res and then
|
|
||||||
attached res.headers as hds
|
|
||||||
then
|
|
||||||
across
|
|
||||||
hds as c
|
|
||||||
loop
|
|
||||||
h.append (c.item.name + ": " + c.item.value + "%R%N")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print (h)
|
|
||||||
else
|
|
||||||
assert ("Has requestbin path", False)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test_post_with_file
|
test_post_with_file
|
||||||
local
|
local
|
||||||
sess: HTTP_CLIENT_SESSION
|
sess: HTTP_CLIENT_SESSION
|
||||||
h: STRING_8
|
|
||||||
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||||
do
|
do
|
||||||
if attached global_requestbin_path as requestbin_path then
|
-- POST REQUEST WITH A FILE
|
||||||
|
-- check requestbin to ensure the form parameters are correctly received
|
||||||
-- POST REQUEST WITH A FILE
|
-- set filename to a local file
|
||||||
-- check requestbin to ensure the form parameters are correctly received
|
sess := new_web_session
|
||||||
-- set filename to a local file
|
create l_ctx.make
|
||||||
sess := new_session ("http://requestb.in")
|
l_ctx.set_upload_filename ("test.txt")
|
||||||
create l_ctx.make
|
if
|
||||||
l_ctx.set_upload_filename ("test.txt")
|
attached sess.post ("", l_ctx, Void) as res
|
||||||
create h.make_empty
|
then
|
||||||
if
|
check_response (res)
|
||||||
attached sess.post (requestbin_path, l_ctx, Void) as res and then
|
|
||||||
attached res.headers as hds
|
|
||||||
then
|
|
||||||
across
|
|
||||||
hds as c
|
|
||||||
loop
|
|
||||||
h.append (c.item.name + ": " + c.item.value + "%R%N")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print (h)
|
|
||||||
else
|
|
||||||
assert ("Has requestbin path", False)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test_put_with_file
|
test_put_with_file
|
||||||
local
|
local
|
||||||
sess: HTTP_CLIENT_SESSION
|
sess: HTTP_CLIENT_SESSION
|
||||||
h: STRING_8
|
|
||||||
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||||
do
|
do
|
||||||
if attached global_requestbin_path as requestbin_path then
|
-- PUT REQUEST WITH A FILE
|
||||||
|
-- check requestbin to ensure the file is correctly received
|
||||||
-- PUT REQUEST WITH A FILE
|
-- set filename to a local file
|
||||||
-- check requestbin to ensure the file is correctly received
|
sess := new_web_session
|
||||||
-- set filename to a local file
|
create l_ctx.make
|
||||||
sess := new_session ("http://requestb.in")
|
l_ctx.set_upload_filename ("test.txt")
|
||||||
create l_ctx.make
|
if
|
||||||
l_ctx.set_upload_filename ("test.txt")
|
attached sess.put ("", l_ctx, Void) as res
|
||||||
create h.make_empty
|
then
|
||||||
if
|
check_response (res)
|
||||||
attached sess.put (requestbin_path, l_ctx, Void) as res and then
|
|
||||||
attached res.headers as hds
|
|
||||||
then
|
|
||||||
across
|
|
||||||
hds as c
|
|
||||||
loop
|
|
||||||
h.append (c.item.name + ": " + c.item.value + "%R%N")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print (h)
|
|
||||||
else
|
|
||||||
assert ("Has requestbin path", False)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test_put_with_data
|
test_put_with_data
|
||||||
local
|
local
|
||||||
sess: HTTP_CLIENT_SESSION
|
sess: HTTP_CLIENT_SESSION
|
||||||
h: STRING_8
|
|
||||||
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||||
do
|
do
|
||||||
if attached global_requestbin_path as requestbin_path then
|
-- PUT REQUEST WITH A FILE
|
||||||
|
-- check requestbin to ensure the file is correctly received
|
||||||
-- PUT REQUEST WITH A FILE
|
-- set filename to a local file
|
||||||
-- check requestbin to ensure the file is correctly received
|
sess := new_web_session
|
||||||
-- set filename to a local file
|
create l_ctx.make
|
||||||
sess := new_session ("http://requestb.in")
|
l_ctx.set_upload_data ("name=This is a test for http client.%N")
|
||||||
create l_ctx.make
|
if
|
||||||
l_ctx.set_upload_data ("name=This is a test for http client.%N")
|
attached sess.put ("", l_ctx, Void) as res
|
||||||
create h.make_empty
|
then
|
||||||
if
|
check_response (res)
|
||||||
attached sess.put (requestbin_path, l_ctx, Void) as res and then
|
|
||||||
attached res.headers as hds
|
|
||||||
then
|
|
||||||
across
|
|
||||||
hds as c
|
|
||||||
loop
|
|
||||||
h.append (c.item.name + ": " + c.item.value + "%R%N")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print (h)
|
|
||||||
else
|
|
||||||
assert ("Has requestbin path", False)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test_post_with_file_and_form_data
|
test_post_with_file_and_form_data
|
||||||
local
|
local
|
||||||
sess: HTTP_CLIENT_SESSION
|
sess: HTTP_CLIENT_SESSION
|
||||||
h: STRING_8
|
|
||||||
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||||
do
|
do
|
||||||
if attached global_requestbin_path as requestbin_path then
|
-- POST REQUEST WITH A FILE AND FORM DATA
|
||||||
|
-- check requestbin to ensure the file and form parameters are correctly received
|
||||||
|
-- set filename to a local file
|
||||||
|
sess := new_web_session
|
||||||
|
create l_ctx.make
|
||||||
|
-- l_ctx.add_file_form_parameter ("image", "test.txt", "image/jpeg")
|
||||||
|
l_ctx.add_file_form_parameter ("text", "test.txt", "plain/text")
|
||||||
|
l_ctx.add_form_parameter ("First", "Value")
|
||||||
|
l_ctx.add_form_parameter ("Second", "and last value")
|
||||||
|
if
|
||||||
|
attached sess.post ("", l_ctx, Void) as res
|
||||||
|
then
|
||||||
|
check_response (res)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- POST REQUEST WITH A FILE AND FORM DATA
|
test_post_with_multiple_file_and_form_data
|
||||||
-- check requestbin to ensure the file and form parameters are correctly received
|
local
|
||||||
-- set filename to a local file
|
sess: HTTP_CLIENT_SESSION
|
||||||
sess := new_session ("http://requestb.in")
|
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||||
-- sess := new_session ("http://localhost:9090")
|
do
|
||||||
create l_ctx.make
|
-- POST REQUEST WITH A FILE AND FORM DATA
|
||||||
-- l_ctx.set_upload_filename ("logo.jpg")
|
-- check requestbin to ensure the file and form parameters are correctly received
|
||||||
l_ctx.set_upload_filename ("test.txt")
|
-- set filename to a local file
|
||||||
l_ctx.add_form_parameter ("First", "Value")
|
sess := new_web_session
|
||||||
l_ctx.add_form_parameter ("Second", "and last value")
|
create l_ctx.make
|
||||||
create h.make_empty
|
l_ctx.add_header ("Content-Type", "multipart/form-data")
|
||||||
if
|
|
||||||
attached sess.post (requestbin_path, l_ctx, Void) as res and then
|
l_ctx.add_file_form_parameter ("first_file", "test.txt", "plain/text")
|
||||||
attached res.headers as hds
|
l_ctx.add_file_form_parameter ("image", "logo.jpg", "image/jpeg")
|
||||||
then
|
l_ctx.add_form_parameter ("First", "Value")
|
||||||
across
|
l_ctx.add_form_parameter ("Second", "and last value")
|
||||||
hds as c
|
l_ctx.add_file_form_parameter ("last_file", "test.txt", Void)
|
||||||
loop
|
|
||||||
h.append (c.item.name + ": " + c.item.value + "%R%N")
|
if
|
||||||
end
|
attached sess.post ("", l_ctx, Void) as res
|
||||||
end
|
then
|
||||||
print (h)
|
check_response (res)
|
||||||
else
|
|
||||||
assert ("Has requestbin path", False)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test_post_with_file_using_chunked_transfer_encoding
|
test_post_with_file_using_chunked_transfer_encoding
|
||||||
local
|
local
|
||||||
sess: HTTP_CLIENT_SESSION
|
sess: HTTP_CLIENT_SESSION
|
||||||
h: STRING_8
|
|
||||||
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||||
do
|
do
|
||||||
if attached global_requestbin_path as requestbin_path then
|
-- POST REQUEST WITH A FILE AND FORM DATA
|
||||||
|
-- check requestbin to ensure the file and form parameters are correctly received
|
||||||
-- POST REQUEST WITH A FILE AND FORM DATA
|
-- set filename to a local file
|
||||||
-- check requestbin to ensure the file and form parameters are correctly received
|
sess := new_web_session
|
||||||
-- set filename to a local file
|
create l_ctx.make
|
||||||
sess := new_session ("http://requestb.in")
|
l_ctx.add_header ("Transfer-Encoding", "chunked")
|
||||||
create l_ctx.make
|
l_ctx.set_upload_filename ("logo.jpg")
|
||||||
l_ctx.add_header ("Transfer-Encoding", "chunked")
|
if
|
||||||
l_ctx.set_upload_filename ("logo.jpg")
|
attached sess.post ("", l_ctx, Void) as res
|
||||||
create h.make_empty
|
then
|
||||||
if
|
check_response (res)
|
||||||
attached sess.post (requestbin_path, l_ctx, Void) as res and then
|
|
||||||
attached res.headers as hds
|
|
||||||
then
|
|
||||||
across
|
|
||||||
hds as c
|
|
||||||
loop
|
|
||||||
h.append (c.item.name + ": " + c.item.value + "%R%N")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print (h)
|
|
||||||
else
|
|
||||||
assert ("Has requestbin path", False)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test_get_with_redirection
|
test_get_with_redirection
|
||||||
local
|
local
|
||||||
sess: HTTP_CLIENT_SESSION
|
sess: HTTP_CLIENT_SESSION
|
||||||
h: STRING_8
|
|
||||||
do
|
do
|
||||||
if attached global_requestbin_path as requestbin_path then
|
-- GET REQUEST, Forwarding (google's first answer is a forward)
|
||||||
|
-- check headers received (printed in console)
|
||||||
-- GET REQUEST, Forwarding (google's first answer is a forward)
|
sess := new_session ("http://google.com")
|
||||||
-- check headers received (printed in console)
|
if attached sess.get ("/", Void) as res then
|
||||||
sess := new_session ("http://google.com")
|
check_response (res)
|
||||||
create h.make_empty
|
assert("was redirected", res.redirections_count > 0)
|
||||||
if attached sess.get ("/", Void) as res and then attached res.headers as hds then
|
|
||||||
assert("was redirected", res.redirections_count > 0)
|
|
||||||
across
|
|
||||||
hds as c
|
|
||||||
loop
|
|
||||||
h.append (c.item.name + ": " + c.item.value + "%R%N")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print (h)
|
|
||||||
else
|
|
||||||
assert ("Has requestbin path", False)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -377,6 +311,7 @@ feature -- Factory
|
|||||||
sess.set_credentials ("test", "test")
|
sess.set_credentials ("test", "test")
|
||||||
create ctx.make_with_credentials_required
|
create ctx.make_with_credentials_required
|
||||||
if attached sess.get ("/password-ok.php", ctx) as res then
|
if attached sess.get ("/password-ok.php", ctx) as res then
|
||||||
|
check_response (res)
|
||||||
if attached {READABLE_STRING_8} res.body as l_body then
|
if attached {READABLE_STRING_8} res.body as l_body then
|
||||||
assert ("Fetch all body, including closing html tag", l_body.has_substring ("</html>"))
|
assert ("Fetch all body, including closing html tag", l_body.has_substring ("</html>"))
|
||||||
else
|
else
|
||||||
@@ -388,50 +323,58 @@ feature -- Factory
|
|||||||
test_get_with_query_parameters
|
test_get_with_query_parameters
|
||||||
local
|
local
|
||||||
sess: HTTP_CLIENT_SESSION
|
sess: HTTP_CLIENT_SESSION
|
||||||
h: STRING_8
|
|
||||||
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||||
q: STRING
|
q: STRING
|
||||||
do
|
do
|
||||||
if attached global_requestbin_path as requestbin_path then
|
-- GET REQUEST WITH A FILE AND FORM DATA
|
||||||
|
-- check requestbin to ensure the file and form parameters are correctly received
|
||||||
-- GET REQUEST WITH A FILE AND FORM DATA
|
-- set filename to a local file
|
||||||
-- check requestbin to ensure the file and form parameters are correctly received
|
sess := new_web_session
|
||||||
-- set filename to a local file
|
create l_ctx.make
|
||||||
sess := new_session ("http://requestb.in")
|
l_ctx.add_query_parameter ("?", "?first&arg")
|
||||||
create l_ctx.make
|
l_ctx.add_query_parameter ("title", "Eiffel World!")
|
||||||
l_ctx.add_query_parameter ("?", "?first&arg")
|
l_ctx.add_query_parameter ("path", "foo/bar")
|
||||||
l_ctx.add_query_parameter ("title", "Eiffel World!")
|
l_ctx.add_query_parameter ("reserved", "+=&?")
|
||||||
l_ctx.add_query_parameter ("path", "foo/bar")
|
l_ctx.add_query_parameter ("unreserved", ":!@'()*")
|
||||||
l_ctx.add_query_parameter ("reserved", "+=&?")
|
l_ctx.add_query_parameter ("unsafe", "%"[]{}")
|
||||||
l_ctx.add_query_parameter ("unreserved", ":!@'()*")
|
l_ctx.add_query_parameter ("test", "!$&'()*")
|
||||||
l_ctx.add_query_parameter ("unsafe", "%"[]{}")
|
l_ctx.add_query_parameter ("a&b", "a&b")
|
||||||
l_ctx.add_query_parameter ("test", "!$&'()*")
|
l_ctx.add_query_parameter ("lst[a][b]", "[abc][123]")
|
||||||
l_ctx.add_query_parameter ("a&b", "a&b")
|
l_ctx.add_query_parameter ("foo(a,b)", "bar(1,2)*pi")
|
||||||
l_ctx.add_query_parameter ("lst[a][b]", "[abc][123]")
|
create q.make_empty
|
||||||
l_ctx.add_query_parameter ("foo(a,b)", "bar(1,2)*pi")
|
l_ctx.append_query_parameters_to_url (q)
|
||||||
create q.make_empty
|
assert("query", q.same_string ("??=?first%%26arg&title=Eiffel+World!&path=foo/bar&reserved=%%2B=%%26?&unreserved=:!@'()*&unsafe=%%22%%5B%%5D%%7B%%7D&test=!$%%26'()*&a%%26b=a%%26b&lst%%5Ba%%5D%%5Bb%%5D=%%5Babc%%5D%%5B123%%5D&foo(a,b)=bar(1,2)*pi"))
|
||||||
l_ctx.append_query_parameters_to_url (q)
|
|
||||||
assert("query", q.same_string ("??=?first%%26arg&title=Eiffel+World!&path=foo/bar&reserved=%%2B=%%26?&unreserved=:!@'()*&unsafe=%%22%%5B%%5D%%7B%%7D&test=!$%%26'()*&a%%26b=a%%26b&lst%%5Ba%%5D%%5Bb%%5D=%%5Babc%%5D%%5B123%%5D&foo(a,b)=bar(1,2)*pi"))
|
|
||||||
|
|
||||||
|
|
||||||
create h.make_empty
|
if
|
||||||
if
|
attached sess.get ("", l_ctx) as res
|
||||||
attached sess.get (requestbin_path, l_ctx) as res and then
|
then
|
||||||
attached res.headers as hds
|
check_response (res)
|
||||||
then
|
|
||||||
across
|
|
||||||
hds as c
|
|
||||||
loop
|
|
||||||
h.append (c.item.name + ": " + c.item.value + "%R%N")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print (h)
|
|
||||||
else
|
|
||||||
assert ("Has requestbin path", False)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
check_response (res: HTTP_CLIENT_RESPONSE)
|
||||||
|
local
|
||||||
|
h: STRING
|
||||||
|
do
|
||||||
|
assert ("ok", not res.error_occurred)
|
||||||
|
create h.make_empty
|
||||||
|
if
|
||||||
|
attached res.headers as hds
|
||||||
|
then
|
||||||
|
across
|
||||||
|
hds as c
|
||||||
|
loop
|
||||||
|
h.append (c.item.name + ": " + c.item.value + "%R%N")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print (h)
|
||||||
|
if attached res.body as b then
|
||||||
|
print (b)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -55,12 +55,19 @@ feature -- Secure connection Helpers
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_secure_protocol_to_ssl_2_or_3
|
set_secure_protocol_to_ssl_2_or_3
|
||||||
-- Set `ssl_protocol' with `Ssl_23'.
|
-- Set `ssl_protocol' with `Ssl_23'.
|
||||||
do
|
-- Protocol not supported anymore.
|
||||||
set_secure_protocol ({SSL_PROTOCOL}.Ssl_23)
|
obsolete
|
||||||
end
|
"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'.
|
-- Set `ssl_protocol' with `Tls_1_0'.
|
||||||
do
|
do
|
||||||
set_secure_protocol ({SSL_PROTOCOL}.Tls_1_0)
|
set_secure_protocol ({SSL_PROTOCOL}.Tls_1_0)
|
||||||
@@ -176,7 +183,14 @@ feature -- Output
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
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)"
|
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
|
end
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
note
|
note
|
||||||
description: "Summary description for {JWS}."
|
description: "Summary description for {JWS}."
|
||||||
author: ""
|
|
||||||
date: "$Date$"
|
date: "$Date$"
|
||||||
revision: "$Revision$"
|
revision: "$Revision$"
|
||||||
|
|
||||||
@@ -9,19 +8,35 @@ class
|
|||||||
|
|
||||||
inherit
|
inherit
|
||||||
JWT
|
JWT
|
||||||
|
redefine
|
||||||
|
default_create
|
||||||
|
end
|
||||||
|
|
||||||
JWT_UTILITIES
|
JWT_UTILITIES
|
||||||
undefine
|
redefine
|
||||||
default_create
|
default_create
|
||||||
end
|
end
|
||||||
|
|
||||||
create
|
create
|
||||||
default_create,
|
default_create,
|
||||||
|
make_with_algorithm,
|
||||||
make_with_claims,
|
make_with_claims,
|
||||||
make_with_json_payload
|
make_with_json_payload
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
default_create
|
||||||
|
do
|
||||||
|
Precursor {JWT}
|
||||||
|
set_algorithm_to_hs256
|
||||||
|
end
|
||||||
|
|
||||||
|
make_with_algorithm (alg: like algorithm)
|
||||||
|
do
|
||||||
|
default_create
|
||||||
|
set_algorithm (alg)
|
||||||
|
end
|
||||||
|
|
||||||
make_with_claims (tb: STRING_TABLE [READABLE_STRING_GENERAL])
|
make_with_claims (tb: STRING_TABLE [READABLE_STRING_GENERAL])
|
||||||
do
|
do
|
||||||
default_create
|
default_create
|
||||||
@@ -77,4 +92,14 @@ feature -- Element change
|
|||||||
header.set_algorithm (alg)
|
header.set_algorithm (alg)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
set_algorithm_to_hs256
|
||||||
|
do
|
||||||
|
set_algorithm (alg_hs256)
|
||||||
|
end
|
||||||
|
|
||||||
|
set_algorithm_to_none
|
||||||
|
do
|
||||||
|
set_algorithm (alg_none)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -118,6 +118,11 @@ feature {JWT_UTILITIES} -- Error reporting
|
|||||||
l_errors.extend (err)
|
l_errors.extend (err)
|
||||||
end
|
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)
|
report_unsupported_alg_error (alg: READABLE_STRING_8)
|
||||||
do
|
do
|
||||||
report_error (create {JWT_UNSUPPORTED_ALG_ERROR}.make (alg))
|
report_error (create {JWT_UNSUPPORTED_ALG_ERROR}.make (alg))
|
||||||
|
|||||||
@@ -259,6 +259,11 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
set_issued_at_now_utc
|
||||||
|
do
|
||||||
|
set_issued_at (create {DATE_TIME}.make_now_utc)
|
||||||
|
end
|
||||||
|
|
||||||
set_jwt_id (jti: detachable READABLE_STRING_8)
|
set_jwt_id (jti: detachable READABLE_STRING_8)
|
||||||
-- The "jti" (JWT ID) claim provides a unique identifier for the JWT.
|
-- The "jti" (JWT ID) claim provides a unique identifier for the JWT.
|
||||||
-- The identifier value MUST be assigned in a manner that ensures that
|
-- The identifier value MUST be assigned in a manner that ensures that
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
note
|
note
|
||||||
description: "Summary description for {JWT_LOADER}."
|
description: "Loader and verifier to JWT token."
|
||||||
author: ""
|
|
||||||
date: "$Date$"
|
date: "$Date$"
|
||||||
revision: "$Revision$"
|
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
|
class
|
||||||
JWT_LOADER
|
JWT_LOADER
|
||||||
@@ -12,9 +12,13 @@ inherit
|
|||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
token (a_token_input: READABLE_STRING_8; a_secret: READABLE_STRING_8; ctx: detachable JWT_CONTEXT): detachable JWT
|
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 secret `a_secret`, and optional context `ctx`
|
-- 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.
|
-- 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
|
local
|
||||||
jws: JWS
|
jws: JWS
|
||||||
i,j,n: INTEGER
|
i,j,n: INTEGER
|
||||||
@@ -29,20 +33,27 @@ feature -- Access
|
|||||||
l_enc_payload := a_token_input.substring (i + 1, j - 1)
|
l_enc_payload := a_token_input.substring (i + 1, j - 1)
|
||||||
l_signature := a_token_input.substring (j + 1, n)
|
l_signature := a_token_input.substring (j + 1, n)
|
||||||
create jws.make_with_json_payload (base64url_decode (l_enc_payload))
|
create jws.make_with_json_payload (base64url_decode (l_enc_payload))
|
||||||
|
|
||||||
alg := signature_algorithm_from_encoded_header (l_enc_header)
|
alg := signature_algorithm_from_encoded_header (l_enc_header)
|
||||||
jws.set_algorithm (alg)
|
if a_alg /= Void then
|
||||||
if alg = Void then
|
if alg /= Void and then not alg.is_case_insensitive_equal_general (a_alg) then
|
||||||
-- Use default
|
jws.report_mismatched_alg_error (a_alg, alg)
|
||||||
alg := alg_hs256
|
else
|
||||||
|
alg := a_alg
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if alg = Void then
|
||||||
|
-- Use default
|
||||||
|
alg := alg_hs256
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
jws.set_algorithm (alg)
|
||||||
check alg_set: alg /= Void end
|
check alg_set: alg /= Void end
|
||||||
if ctx = Void or else not ctx.validation_ignored then
|
if ctx = Void or else not ctx.validation_ignored then
|
||||||
if not is_supporting_signature_algorithm (alg) then
|
if not is_supporting_signature_algorithm (alg) then
|
||||||
jws.report_unsupported_alg_error (alg)
|
jws.report_unsupported_alg_error (alg)
|
||||||
alg := alg_hs256
|
alg := alg_hs256
|
||||||
end
|
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
|
jws.report_unverified_token_error
|
||||||
end
|
end
|
||||||
if
|
if
|
||||||
|
|||||||
@@ -54,7 +54,14 @@ feature -- Test
|
|||||||
|
|
||||||
create jwt_loader
|
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 ("no error", not l_tok.has_error)
|
||||||
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||||
end
|
end
|
||||||
@@ -96,21 +103,21 @@ feature -- Test
|
|||||||
create jwt_loader
|
create jwt_loader
|
||||||
|
|
||||||
-- Test with validation + exp
|
-- 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 ("no error", not l_tok.has_error)
|
||||||
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||||
end
|
end
|
||||||
|
|
||||||
create ctx
|
create ctx
|
||||||
ctx.set_time (now)
|
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)
|
assert ("no error", not l_tok.has_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
dt := duplicated_time (now)
|
dt := duplicated_time (now)
|
||||||
dt.hour_add (5)
|
dt.hour_add (5)
|
||||||
ctx.set_time (dt)
|
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)
|
assert ("exp error", l_tok.has_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -122,7 +129,7 @@ feature -- Test
|
|||||||
tok := jwt.encoded_string ("secret")
|
tok := jwt.encoded_string ("secret")
|
||||||
|
|
||||||
ctx.set_time (now)
|
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)
|
assert ("has nbf error", l_tok.has_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -130,7 +137,7 @@ feature -- Test
|
|||||||
dt.second_add (15)
|
dt.second_add (15)
|
||||||
ctx.set_time (dt)
|
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)
|
assert ("has nbf error", l_tok.has_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -138,31 +145,51 @@ feature -- Test
|
|||||||
dt.minute_add (45)
|
dt.minute_add (45)
|
||||||
ctx.set_time (dt)
|
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)
|
assert ("no error", not l_tok.has_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Test Issuer
|
-- Test Issuer
|
||||||
ctx.set_issuer ("urn:foobar")
|
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)
|
assert ("has iss error", l_tok.has_error)
|
||||||
end
|
end
|
||||||
ctx.set_issuer ("urn:foo")
|
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)
|
assert ("no error", not l_tok.has_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Test Audience
|
-- Test Audience
|
||||||
ctx.set_audience ("urn:foobar")
|
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)
|
assert ("has aud error", l_tok.has_error)
|
||||||
end
|
end
|
||||||
ctx.set_audience ("urn:foo")
|
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)
|
assert ("no error", not l_tok.has_error)
|
||||||
end
|
end
|
||||||
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
|
test_unsecured_jwt
|
||||||
local
|
local
|
||||||
jwt: JWS
|
jwt: JWS
|
||||||
@@ -177,7 +204,11 @@ feature -- Test
|
|||||||
jwt.set_algorithm ("none")
|
jwt.set_algorithm ("none")
|
||||||
tok := jwt.encoded_string ("secret")
|
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 ("no error", not jwt.has_error)
|
||||||
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
assert ("same payload", l_tok.claimset.string.same_string (payload))
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_socket_timeout (a_nb_seconds: like socket_timeout)
|
set_socket_timeout (a_nb_seconds: like socket_timeout)
|
||||||
-- Set `socket_timeout' with `a_nb_seconds'
|
-- Set `socket_timeout' with `a_nb_seconds'.
|
||||||
do
|
do
|
||||||
socket_timeout := a_nb_seconds
|
socket_timeout := a_nb_seconds
|
||||||
ensure
|
ensure
|
||||||
@@ -175,7 +175,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_socket_recv_timeout (a_nb_seconds: like socket_recv_timeout)
|
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
|
do
|
||||||
socket_recv_timeout := a_nb_seconds
|
socket_recv_timeout := a_nb_seconds
|
||||||
ensure
|
ensure
|
||||||
@@ -183,7 +183,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_keep_alive_timeout (a_seconds: like keep_alive_timeout)
|
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
|
do
|
||||||
keep_alive_timeout := a_seconds
|
keep_alive_timeout := a_seconds
|
||||||
ensure
|
ensure
|
||||||
@@ -191,7 +191,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_max_keep_alive_requests (nb: like max_keep_alive_requests)
|
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
|
do
|
||||||
max_keep_alive_requests := nb
|
max_keep_alive_requests := nb
|
||||||
ensure
|
ensure
|
||||||
@@ -254,7 +254,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
mark_secure
|
mark_secure
|
||||||
-- Set is_secure in True
|
-- Set is_secure in True.
|
||||||
do
|
do
|
||||||
set_is_secure (True)
|
set_is_secure (True)
|
||||||
ensure
|
ensure
|
||||||
@@ -287,7 +287,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_secure_protocol (a_version: NATURAL)
|
set_secure_protocol (a_version: NATURAL)
|
||||||
-- Set `secure_protocol' with `a_version'
|
-- Set `secure_protocol' with `a_version'.
|
||||||
do
|
do
|
||||||
secure_protocol := a_version
|
secure_protocol := a_version
|
||||||
ensure
|
ensure
|
||||||
@@ -295,7 +295,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
set_secure_protocol_from_string (a_ssl_version: READABLE_STRING_GENERAL)
|
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
|
do
|
||||||
if a_ssl_version.is_case_insensitive_equal ("ssl_2_3") then
|
if a_ssl_version.is_case_insensitive_equal ("ssl_2_3") then
|
||||||
set_secure_protocol_to_ssl_2_or_3
|
set_secure_protocol_to_ssl_2_or_3
|
||||||
@@ -316,6 +316,8 @@ feature -- SSL Helpers
|
|||||||
|
|
||||||
set_secure_protocol_to_ssl_2_or_3
|
set_secure_protocol_to_ssl_2_or_3
|
||||||
-- Set `secure_protocol' with `Ssl_23'.
|
-- Set `secure_protocol' with `Ssl_23'.
|
||||||
|
obsolete
|
||||||
|
"Use set_secure_protocol_to_tls_1_2 [2017-06-23]."
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -36,9 +36,16 @@ feature -- Access
|
|||||||
feature -- SSL Helpers
|
feature -- SSL Helpers
|
||||||
|
|
||||||
set_secure_protocol_to_ssl_2_or_3
|
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
|
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
|
end
|
||||||
|
|
||||||
set_secure_protocol_to_tls_1_0
|
set_secure_protocol_to_tls_1_0
|
||||||
@@ -67,7 +74,7 @@ feature -- SSL Helpers
|
|||||||
|
|
||||||
|
|
||||||
note
|
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)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -28,17 +28,17 @@ feature -- Access
|
|||||||
end
|
end
|
||||||
|
|
||||||
message: detachable READABLE_STRING_32
|
message: detachable READABLE_STRING_32
|
||||||
-- Potential error message
|
-- Potential error message.
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
parent: detachable ERROR
|
parent: detachable ERROR
|
||||||
-- Eventual error prior to Current
|
-- Eventual error prior to Current.
|
||||||
|
|
||||||
feature -- String representation
|
feature -- String representation
|
||||||
|
|
||||||
string_representation: STRING_32
|
string_representation: STRING_32
|
||||||
-- String representation for Current
|
-- String representation for Current.
|
||||||
do
|
do
|
||||||
create Result.make_from_string (name.as_string_32)
|
create Result.make_from_string (name.as_string_32)
|
||||||
Result.append_character (' ')
|
Result.append_character (' ')
|
||||||
@@ -62,7 +62,7 @@ feature -- Status report
|
|||||||
feature -- Change
|
feature -- Change
|
||||||
|
|
||||||
set_parent (a_parent: like parent)
|
set_parent (a_parent: like parent)
|
||||||
-- Set `parent' to `a_parent'
|
-- Set `parent' to `a_parent'.
|
||||||
do
|
do
|
||||||
parent := a_parent
|
parent := a_parent
|
||||||
end
|
end
|
||||||
@@ -80,7 +80,7 @@ invariant
|
|||||||
name_attached: name /= Void
|
name_attached: name /= Void
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -30,28 +30,24 @@ feature -- Access
|
|||||||
|
|
||||||
name: STRING
|
name: STRING
|
||||||
|
|
||||||
message: detachable STRING_32
|
message: STRING_32
|
||||||
do
|
do
|
||||||
create Result.make_from_string (name)
|
create Result.make_from_string (name)
|
||||||
from
|
across
|
||||||
sub_errors.start
|
sub_errors as s
|
||||||
until
|
|
||||||
sub_errors.after
|
|
||||||
loop
|
loop
|
||||||
if
|
if
|
||||||
attached sub_errors.item as e and then
|
attached s.item as e and then
|
||||||
attached e.message as m
|
attached e.message as m
|
||||||
then
|
then
|
||||||
|
|
||||||
Result.append_character ('%N')
|
Result.append_character ('%N')
|
||||||
Result.append_string (m)
|
Result.append_string (m)
|
||||||
end
|
end
|
||||||
sub_errors.forth
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
sub_errors: LIST [ERROR]
|
sub_errors: LIST [ERROR]
|
||||||
-- Error contained by Current
|
-- Error contained by Current.
|
||||||
|
|
||||||
feature -- Visitor
|
feature -- Visitor
|
||||||
|
|
||||||
@@ -61,9 +57,8 @@ feature -- Visitor
|
|||||||
a_visitor.process_group (Current)
|
a_visitor.process_group (Current)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
note
|
note
|
||||||
description : "[
|
description : "Error handler or receiver."
|
||||||
Error handler or receiver.
|
|
||||||
|
|
||||||
]"
|
|
||||||
legal: "See notice at end of class."
|
legal: "See notice at end of class."
|
||||||
status: "See notice at end of class."
|
status: "See notice at end of class."
|
||||||
date: "$Date: 2015-10-10 00:55:41 +0200 (sam., 10 oct. 2015) $"
|
date: "$Date$"
|
||||||
revision: "$Revision: 97980 $"
|
revision: "$Revision$"
|
||||||
|
|
||||||
class
|
class
|
||||||
ERROR_HANDLER
|
ERROR_HANDLER
|
||||||
|
|
||||||
inherit
|
inherit
|
||||||
ANY
|
|
||||||
|
|
||||||
DEBUG_OUTPUT
|
DEBUG_OUTPUT
|
||||||
|
|
||||||
create
|
create
|
||||||
@@ -46,7 +41,7 @@ feature -- Access
|
|||||||
-- Optional identifier for Current handler.
|
-- Optional identifier for Current handler.
|
||||||
|
|
||||||
primary_error_code: INTEGER
|
primary_error_code: INTEGER
|
||||||
-- Code of first error in `errors'
|
-- Code of first error in `errors'.
|
||||||
require
|
require
|
||||||
at_least_one_error: has_error
|
at_least_one_error: has_error
|
||||||
do
|
do
|
||||||
@@ -62,7 +57,7 @@ feature -- Status
|
|||||||
end
|
end
|
||||||
|
|
||||||
count: INTEGER
|
count: INTEGER
|
||||||
-- Number of error
|
-- Number of error.
|
||||||
do
|
do
|
||||||
Result := errors.count
|
Result := errors.count
|
||||||
end
|
end
|
||||||
@@ -83,7 +78,7 @@ feature -- Status
|
|||||||
feature {ERROR_HANDLER, ERROR_VISITOR} -- Restricted access
|
feature {ERROR_HANDLER, ERROR_VISITOR} -- Restricted access
|
||||||
|
|
||||||
errors: LIST [ERROR]
|
errors: LIST [ERROR]
|
||||||
-- Errors container
|
-- Errors container.
|
||||||
|
|
||||||
feature -- Status report
|
feature -- Status report
|
||||||
|
|
||||||
@@ -119,12 +114,12 @@ feature -- Status report
|
|||||||
feature -- Events
|
feature -- Events
|
||||||
|
|
||||||
error_added_actions: ACTION_SEQUENCE [TUPLE [ERROR]]
|
error_added_actions: ACTION_SEQUENCE [TUPLE [ERROR]]
|
||||||
-- Actions triggered when a new error is added
|
-- Actions triggered when a new error is added.
|
||||||
|
|
||||||
feature -- Synchronization
|
feature -- Synchronization
|
||||||
|
|
||||||
add_synchronization (h: ERROR_HANDLER)
|
add_synchronization (h: ERROR_HANDLER)
|
||||||
-- Add synchronization between `h' and `Current'
|
-- Add synchronization between `h' and `Current`.
|
||||||
--| the same handler can be added more than once
|
--| the same handler can be added more than once
|
||||||
--| it will be synchronized only once
|
--| it will be synchronized only once
|
||||||
do
|
do
|
||||||
@@ -133,7 +128,7 @@ feature -- Synchronization
|
|||||||
end
|
end
|
||||||
|
|
||||||
remove_synchronization (h: ERROR_HANDLER)
|
remove_synchronization (h: ERROR_HANDLER)
|
||||||
-- Remove synchronization between `h' and `Current'
|
-- Remove synchronization between `h' and `Current'.
|
||||||
do
|
do
|
||||||
remove_propagation (h)
|
remove_propagation (h)
|
||||||
h.remove_propagation (Current)
|
h.remove_propagation (Current)
|
||||||
@@ -347,7 +342,7 @@ feature {NONE} -- Event: implementation
|
|||||||
end
|
end
|
||||||
|
|
||||||
on_reset
|
on_reset
|
||||||
-- `reset' was just called
|
-- `reset' was just called.
|
||||||
local
|
local
|
||||||
sync_list: detachable ARRAYED_LIST [ERROR_HANDLER]
|
sync_list: detachable ARRAYED_LIST [ERROR_HANDLER]
|
||||||
lst: detachable LIST [ERROR_HANDLER]
|
lst: detachable LIST [ERROR_HANDLER]
|
||||||
@@ -389,7 +384,7 @@ feature {NONE} -- Event: implementation
|
|||||||
feature -- Basic operation
|
feature -- Basic operation
|
||||||
|
|
||||||
add_error (a_error: ERROR)
|
add_error (a_error: ERROR)
|
||||||
-- Add `a_error' to the stack of error
|
-- Add `a_error' to the stack of error.
|
||||||
do
|
do
|
||||||
errors.force (a_error)
|
errors.force (a_error)
|
||||||
on_error_added (a_error)
|
on_error_added (a_error)
|
||||||
@@ -406,28 +401,22 @@ feature -- Basic operation
|
|||||||
end
|
end
|
||||||
|
|
||||||
add_error_details, add_custom_error (a_code: INTEGER; a_name: STRING; a_message: detachable READABLE_STRING_GENERAL)
|
add_error_details, add_custom_error (a_code: INTEGER; a_name: STRING; a_message: detachable READABLE_STRING_GENERAL)
|
||||||
-- Add custom error to the stack of error
|
-- Add custom error to the stack of error.
|
||||||
local
|
|
||||||
e: ERROR_CUSTOM
|
|
||||||
do
|
do
|
||||||
create e.make (a_code, a_name, a_message)
|
add_error (create {ERROR_CUSTOM}.make (a_code, a_name, a_message))
|
||||||
add_error (e)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
append (other: ERROR_HANDLER)
|
append (other: ERROR_HANDLER)
|
||||||
-- Append errors from `a_err_handler'
|
-- Append errors from `a_err_handler'.
|
||||||
local
|
local
|
||||||
other_errs: LIST [ERROR]
|
other_errs: LIST [ERROR]
|
||||||
do
|
do
|
||||||
other_errs := other.errors
|
other_errs := other.errors
|
||||||
if other_errs.count > 0 then
|
if other_errs /= errors and then other_errs.count > 0 then
|
||||||
from
|
across
|
||||||
other_errs.start
|
other_errs as e
|
||||||
until
|
|
||||||
other_errs.after
|
|
||||||
loop
|
loop
|
||||||
add_error (other_errs.item)
|
add_error (e.item)
|
||||||
other_errs.forth
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
@@ -435,7 +424,7 @@ feature -- Basic operation
|
|||||||
new_count: count = old count + other.count
|
new_count: count = old count + other.count
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Access
|
feature -- Conversion
|
||||||
|
|
||||||
as_single_error: detachable ERROR
|
as_single_error: detachable ERROR
|
||||||
-- All error(s) concatenated into one single error.
|
-- All error(s) concatenated into one single error.
|
||||||
@@ -465,7 +454,7 @@ feature -- Access
|
|||||||
feature -- Element changes
|
feature -- Element changes
|
||||||
|
|
||||||
concatenate
|
concatenate
|
||||||
-- Concatenate into a single error if any
|
-- Concatenate into a single error if any.
|
||||||
do
|
do
|
||||||
if count > 1 and then attached as_single_error as e then
|
if count > 1 and then attached as_single_error as e then
|
||||||
reset
|
reset
|
||||||
@@ -516,7 +505,7 @@ invariant
|
|||||||
propagators_not_empty: attached propagators as lst implies not lst.is_empty
|
propagators_not_empty: attached propagators as lst implies not lst.is_empty
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2016, Jocelyn Fiat, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -25,19 +25,16 @@ feature -- Access
|
|||||||
process_group (g: ERROR_GROUP)
|
process_group (g: ERROR_GROUP)
|
||||||
do
|
do
|
||||||
if attached g.sub_errors as err then
|
if attached g.sub_errors as err then
|
||||||
from
|
across
|
||||||
err.start
|
err as e
|
||||||
until
|
|
||||||
err.after
|
|
||||||
loop
|
loop
|
||||||
process_error (err.item)
|
process_error (e.item)
|
||||||
err.forth
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ inherit
|
|||||||
create
|
create
|
||||||
make
|
make
|
||||||
|
|
||||||
feature -- Initialization
|
feature {NONE} -- Creation
|
||||||
|
|
||||||
make (f: like file)
|
make (f: like file)
|
||||||
require
|
require
|
||||||
@@ -32,7 +32,7 @@ feature -- Access
|
|||||||
feature -- Output
|
feature -- Output
|
||||||
|
|
||||||
output_string (a_str: detachable READABLE_STRING_GENERAL)
|
output_string (a_str: detachable READABLE_STRING_GENERAL)
|
||||||
-- Output Unicode string
|
-- Output Unicode string.
|
||||||
do
|
do
|
||||||
if a_str /= Void then
|
if a_str /= Void then
|
||||||
to_implement ("Convert into UTF-8 or console encoding before output")
|
to_implement ("Convert into UTF-8 or console encoding before output")
|
||||||
@@ -51,7 +51,7 @@ feature -- Output
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ inherit
|
|||||||
feature -- Output
|
feature -- Output
|
||||||
|
|
||||||
output_string (a_str: detachable READABLE_STRING_GENERAL)
|
output_string (a_str: detachable READABLE_STRING_GENERAL)
|
||||||
-- Output Unicode string
|
-- Output Unicode string.
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
output_any (obj: detachable ANY)
|
output_any (obj: detachable ANY)
|
||||||
-- Output Unicode string
|
-- Output Unicode string.
|
||||||
do
|
do
|
||||||
if attached {READABLE_STRING_GENERAL} obj as l_str then
|
if attached {READABLE_STRING_GENERAL} obj as l_str then
|
||||||
to_implement ("Convert into UTF-8 or console encoding before output")
|
to_implement ("Convert into UTF-8 or console encoding before output")
|
||||||
@@ -42,6 +42,7 @@ feature -- Output
|
|||||||
feature -- Process
|
feature -- Process
|
||||||
|
|
||||||
process_error (e: ERROR)
|
process_error (e: ERROR)
|
||||||
|
-- <Precursor>
|
||||||
do
|
do
|
||||||
output_string ({STRING_32}"Error Name: ")
|
output_string ({STRING_32}"Error Name: ")
|
||||||
output_string (e.name)
|
output_string (e.name)
|
||||||
@@ -54,6 +55,7 @@ feature -- Process
|
|||||||
end
|
end
|
||||||
|
|
||||||
process_custom (e: ERROR_CUSTOM)
|
process_custom (e: ERROR_CUSTOM)
|
||||||
|
-- <Precursor>
|
||||||
do
|
do
|
||||||
output_string ({STRING_32}"Error Name: ")
|
output_string ({STRING_32}"Error Name: ")
|
||||||
output_string (e.name)
|
output_string (e.name)
|
||||||
@@ -66,22 +68,19 @@ feature -- Process
|
|||||||
end
|
end
|
||||||
|
|
||||||
process_group (g: ERROR_GROUP)
|
process_group (g: ERROR_GROUP)
|
||||||
|
-- <Precursor>
|
||||||
local
|
local
|
||||||
l_errors: LIST [ERROR]
|
l_errors: LIST [ERROR]
|
||||||
do
|
do
|
||||||
from
|
across
|
||||||
l_errors := g.sub_errors
|
g.sub_errors as s
|
||||||
l_errors.start
|
|
||||||
until
|
|
||||||
l_errors.after
|
|
||||||
loop
|
loop
|
||||||
l_errors.item.process (Current)
|
s.item.process (Current)
|
||||||
l_errors.forth
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ inherit
|
|||||||
create
|
create
|
||||||
make
|
make
|
||||||
|
|
||||||
feature -- Initialization
|
feature {NONE} -- Creation
|
||||||
|
|
||||||
make (buf: like buffer)
|
make (buf: like buffer)
|
||||||
require
|
require
|
||||||
@@ -32,7 +32,7 @@ feature -- Access
|
|||||||
feature -- Output
|
feature -- Output
|
||||||
|
|
||||||
output_string (a_str: detachable READABLE_STRING_GENERAL)
|
output_string (a_str: detachable READABLE_STRING_GENERAL)
|
||||||
-- Output Unicode string
|
-- Output Unicode string.
|
||||||
do
|
do
|
||||||
if a_str /= Void then
|
if a_str /= Void then
|
||||||
to_implement ("Convert into UTF-8 or console encoding before output")
|
to_implement ("Convert into UTF-8 or console encoding before output")
|
||||||
@@ -51,7 +51,7 @@ feature -- Output
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2012, Eiffel Software and others"
|
copyright: "2011-2017, Jocelyn Fiat, Eiffel Software and others"
|
||||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
source: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -100,6 +100,10 @@ echo Install library: http_authorization
|
|||||||
%SAFE_MD% %TMP_CONTRIB_DIR%\library\web\authentication
|
%SAFE_MD% %TMP_CONTRIB_DIR%\library\web\authentication
|
||||||
%COPYCMD% %TMP_DIR%\library\server\authentication\http_authorization %TMP_CONTRIB_DIR%\library\web\authentication\http_authorization
|
%COPYCMD% %TMP_DIR%\library\server\authentication\http_authorization %TMP_CONTRIB_DIR%\library\web\authentication\http_authorization
|
||||||
|
|
||||||
|
echo Install library: jwt
|
||||||
|
%SAFE_MD% %TMP_CONTRIB_DIR%\library\web\authentication
|
||||||
|
%COPYCMD% %TMP_DIR%\library\security\jwt %TMP_CONTRIB_DIR%\library\web\authentication\jwt
|
||||||
|
|
||||||
echo Install library: openid
|
echo Install library: openid
|
||||||
%SAFE_MD% %TMP_CONTRIB_DIR%\library\web\authentication
|
%SAFE_MD% %TMP_CONTRIB_DIR%\library\web\authentication
|
||||||
%COPYCMD% %TMP_DIR%\library\security\openid %TMP_CONTRIB_DIR%\library\web\authentication\openid
|
%COPYCMD% %TMP_DIR%\library\security\openid %TMP_CONTRIB_DIR%\library\web\authentication\openid
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
This example is a simple service that analyze the request and return a formatted output of the request data (query parameters, form parameters, environment variables, and so on). It could be used to debug client, or to experiment the EiffelWeb behavior on various connectors (standalone, apache, iis, ...).
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Effective class for APPLICATION_LAUNCHER_I
|
||||||
|
|
||||||
|
You can put modification in this class
|
||||||
|
]"
|
||||||
|
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
|
||||||
|
revision: "$Revision: 36 $"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION_LAUNCHER [G -> WSF_EXECUTION create make end]
|
||||||
|
|
||||||
|
inherit
|
||||||
|
APPLICATION_LAUNCHER_I [G]
|
||||||
|
|
||||||
|
feature -- Custom
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Specific application launcher
|
||||||
|
|
||||||
|
DO NOT EDIT THIS CLASS
|
||||||
|
|
||||||
|
you can customize APPLICATION_LAUNCHER
|
||||||
|
]"
|
||||||
|
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
|
||||||
|
revision: "$Revision: 36 $"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
APPLICATION_LAUNCHER_I [G -> WSF_EXECUTION create make end]
|
||||||
|
|
||||||
|
inherit
|
||||||
|
SHARED_EXECUTION_ENVIRONMENT
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
nature: like launcher_nature
|
||||||
|
do
|
||||||
|
nature := launcher_nature
|
||||||
|
if nature = Void or else nature = nature_standalone then
|
||||||
|
launch_standalone (opts)
|
||||||
|
elseif nature = nature_cgi then
|
||||||
|
launch_cgi (opts)
|
||||||
|
elseif nature = nature_libfcgi then
|
||||||
|
launch_libfcgi (opts)
|
||||||
|
else
|
||||||
|
-- bye bye
|
||||||
|
(create {EXCEPTIONS}).die (-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Access
|
||||||
|
|
||||||
|
launcher_nature: detachable READABLE_STRING_8
|
||||||
|
-- Initialize the launcher nature
|
||||||
|
-- either cgi, libfcgi, or standalone.
|
||||||
|
--| We could extend with more connector if needed.
|
||||||
|
--| and we could use WSF_DEFAULT_SERVICE_LAUNCHER to configure this at compilation time.
|
||||||
|
local
|
||||||
|
p: PATH
|
||||||
|
ext: detachable READABLE_STRING_32
|
||||||
|
do
|
||||||
|
create p.make_from_string (execution_environment.arguments.command_name)
|
||||||
|
if attached p.entry as l_entry then
|
||||||
|
ext := l_entry.extension
|
||||||
|
end
|
||||||
|
if ext /= Void then
|
||||||
|
if ext.same_string (nature_standalone) then
|
||||||
|
Result := nature_standalone
|
||||||
|
end
|
||||||
|
if ext.same_string (nature_cgi) then
|
||||||
|
Result := nature_cgi
|
||||||
|
end
|
||||||
|
if ext.same_string (nature_libfcgi) or else ext.same_string ("fcgi") then
|
||||||
|
Result := nature_libfcgi
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Result := nature_standalone
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Standalone
|
||||||
|
|
||||||
|
nature_standalone: STRING = "standalone"
|
||||||
|
|
||||||
|
launch_standalone (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_STANDALONE_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- cgi
|
||||||
|
|
||||||
|
nature_cgi: STRING = "cgi"
|
||||||
|
|
||||||
|
launch_cgi (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_CGI_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- libfcgi
|
||||||
|
|
||||||
|
nature_libfcgi: STRING = "libfcgi"
|
||||||
|
|
||||||
|
launch_libfcgi (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_LIBFCGI_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Effective class for APPLICATION_LAUNCHER_I
|
||||||
|
|
||||||
|
You can put modification in this class
|
||||||
|
]"
|
||||||
|
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
|
||||||
|
revision: "$Revision: 36 $"
|
||||||
|
|
||||||
|
class
|
||||||
|
APPLICATION_LAUNCHER [G -> WSF_EXECUTION create make end]
|
||||||
|
|
||||||
|
inherit
|
||||||
|
APPLICATION_LAUNCHER_I [G]
|
||||||
|
|
||||||
|
feature -- Custom
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Specific application launcher
|
||||||
|
|
||||||
|
DO NOT EDIT THIS CLASS
|
||||||
|
|
||||||
|
you can customize APPLICATION_LAUNCHER
|
||||||
|
]"
|
||||||
|
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
|
||||||
|
revision: "$Revision: 36 $"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
APPLICATION_LAUNCHER_I [G -> WSF_EXECUTION create make end]
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
launch (opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
|
||||||
|
local
|
||||||
|
launcher: WSF_SERVICE_LAUNCHER [G]
|
||||||
|
do
|
||||||
|
create {WSF_DEFAULT_SERVICE_LAUNCHER [G]} launcher.make_and_launch (opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-15-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-15-0 http://www.eiffel.com/developers/xml/configuration-1-15-0.xsd" name="requestbin" uuid="FF1E47E3-7677-4E1C-9459-2E2C2341325A">
|
||||||
|
<target name="common" abstract="true">
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
<exclude>/CVS$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" void_safety="all">
|
||||||
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<setting name="console_application" value="true"/>
|
||||||
|
<setting name="concurrency" value="scoop"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="encoder" location="..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||||
|
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf"/>
|
||||||
|
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
|
||||||
|
<library name="wsf_extension" location="..\..\library\server\wsf\wsf_extension-safe.ecf" readonly="false"/>
|
||||||
|
</target>
|
||||||
|
<target name="requestbin_any" extends="common">
|
||||||
|
<root class="EWF_REQUESTBIN_SERVER" feature="make_and_launch"/>
|
||||||
|
<setting name="concurrency" value="scoop"/>
|
||||||
|
<library name="cgi" location="..\..\library\server\wsf\connector\cgi-safe.ecf" readonly="false"/>
|
||||||
|
<library name="libfcgi" location="..\..\library\server\wsf\connector\libfcgi-safe.ecf" readonly="false"/>
|
||||||
|
<library name="standalone" location="..\..\library\server\wsf\connector\standalone-safe.ecf" readonly="false"/>
|
||||||
|
<cluster name="launcher" location=".\launcher\any\" recursive="true"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="requestbin" extends="common">
|
||||||
|
<root class="EWF_REQUESTBIN_SERVER" feature="make_and_launch"/>
|
||||||
|
<setting name="concurrency" value="scoop"/>
|
||||||
|
<library name="default_standalone" location="..\..\library\server\wsf\default\standalone-safe.ecf" readonly="false"/>
|
||||||
|
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="requestbin_cgi" extends="common">
|
||||||
|
<root class="EWF_REQUESTBIN_SERVER" feature="make_and_launch"/>
|
||||||
|
<library name="default_cgi" location="..\..\library\server\wsf\default\cgi-safe.ecf" readonly="false"/>
|
||||||
|
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
<target name="requestbin_libfcgi" extends="common">
|
||||||
|
<root class="EWF_REQUESTBIN_SERVER" feature="make_and_launch"/>
|
||||||
|
<library name="default_libfcgi" location="..\..\library\server\wsf\default\libfcgi-safe.ecf"/>
|
||||||
|
<cluster name="launcher" location=".\launcher\default\" recursive="true"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
port=9090
|
||||||
|
verbose=true
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {EWF_DEBUG_EXECUTION}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
EWF_DEBUG_EXECUTION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_EXECUTION
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
execute
|
||||||
|
local
|
||||||
|
dbg: WSF_DEBUG_HANDLER
|
||||||
|
do
|
||||||
|
response.put_error ("DEBUG uri=" + request.request_uri + "%N")
|
||||||
|
create dbg.make
|
||||||
|
dbg.execute_starts_with ("", request, response)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
application service
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
EWF_REQUESTBIN_SERVER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_LAUNCHABLE_SERVICE
|
||||||
|
redefine
|
||||||
|
initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
APPLICATION_LAUNCHER [EWF_DEBUG_EXECUTION]
|
||||||
|
|
||||||
|
create
|
||||||
|
make_and_launch
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
initialize
|
||||||
|
-- Initialize current service.
|
||||||
|
do
|
||||||
|
Precursor
|
||||||
|
-- set_service_option ("verbose", True)
|
||||||
|
set_service_option ("port", 9090)
|
||||||
|
-- set_service_option ("base", "/www-debug/debug_service.fcgi/")
|
||||||
|
import_service_options (create {WSF_SERVICE_LAUNCHER_OPTIONS_FROM_INI}.make_from_file ("server.ini"))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
@@ -65,7 +65,9 @@ echo Uninstall library: content_negotiation
|
|||||||
%RDCMD% %TMP_CONTRIB_DIR%\library\network\protocol\content_negotiation
|
%RDCMD% %TMP_CONTRIB_DIR%\library\network\protocol\content_negotiation
|
||||||
echo Uninstall library: http_authorization
|
echo Uninstall library: http_authorization
|
||||||
%RDCMD% %TMP_CONTRIB_DIR%\library\web\authentication\http_authorization
|
%RDCMD% %TMP_CONTRIB_DIR%\library\web\authentication\http_authorization
|
||||||
echo Uninstall library: security\openid
|
echo Uninstall library: jwt
|
||||||
|
%RDCMD% %TMP_CONTRIB_DIR%\library\web\authentication\jwt
|
||||||
|
echo Uninstall library: openid
|
||||||
%RDCMD% %TMP_CONTRIB_DIR%\library\web\authentication\openid
|
%RDCMD% %TMP_CONTRIB_DIR%\library\web\authentication\openid
|
||||||
echo Uninstall library: uri_template
|
echo Uninstall library: uri_template
|
||||||
%RDCMD% %TMP_CONTRIB_DIR%\library\text\parser\uri_template
|
%RDCMD% %TMP_CONTRIB_DIR%\library\text\parser\uri_template
|
||||||
|
|||||||
Reference in New Issue
Block a user