Compare commits
3 Commits
es_rev1003
...
es_rev1004
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c83b9d4231 | ||
|
|
69b5ce637e | ||
|
|
485a3812d9 |
24
CHANGELOG.md
24
CHANGELOG.md
@@ -8,12 +8,36 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
### 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:
|
||||||
|
Improved query and form data encoding (based on a very early version of the general URI percent-encoding rules).
|
||||||
|
- 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
|
||||||
|
|
||||||
|
|
||||||
|
## [v1.0.5] - 2017-05-17
|
||||||
|
### Changed
|
||||||
|
- http_network:
|
||||||
|
Integrated changes on SOCKET so that EiffelWeb can be compiled with 16.05 to 17.05 and after.
|
||||||
|
### Fixed
|
||||||
|
- http_client:
|
||||||
|
Improved query and form data encoding (based on a very early version of the general URI percent-encoding rules).
|
||||||
|
- 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.
|
||||||
|
|
||||||
## [v1.0.4] - 2017-03-15
|
## [v1.0.4] - 2017-03-15
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
</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="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>
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
</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="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>
|
||||||
|
|||||||
@@ -196,73 +196,8 @@ feature -- Settings
|
|||||||
Result := session.is_insecure
|
Result := session.is_insecure
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Utilities
|
|
||||||
|
|
||||||
append_parameters_to_url (a_parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_32]; a_url: STRING)
|
|
||||||
-- Append parameters `a_parameters' to `a_url'
|
|
||||||
require
|
|
||||||
a_url_attached: a_url /= Void
|
|
||||||
local
|
|
||||||
l_first_param: BOOLEAN
|
|
||||||
do
|
|
||||||
if a_parameters.count > 0 then
|
|
||||||
if a_url.index_of ('?', 1) > 0 then
|
|
||||||
l_first_param := False
|
|
||||||
elseif a_url.index_of ('&', 1) > 0 then
|
|
||||||
l_first_param := False
|
|
||||||
else
|
|
||||||
l_first_param := True
|
|
||||||
end
|
|
||||||
|
|
||||||
from
|
|
||||||
a_parameters.start
|
|
||||||
until
|
|
||||||
a_parameters.after
|
|
||||||
loop
|
|
||||||
if l_first_param then
|
|
||||||
a_url.append_character ('?')
|
|
||||||
else
|
|
||||||
a_url.append_character ('&')
|
|
||||||
end
|
|
||||||
a_url.append (urlencode (a_parameters.key_for_iteration))
|
|
||||||
a_url.append_character ('=')
|
|
||||||
a_url.append (urlencode (a_parameters.item_for_iteration))
|
|
||||||
l_first_param := False
|
|
||||||
a_parameters.forth
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Utilities: encoding
|
|
||||||
|
|
||||||
url_encoder: URL_ENCODER
|
|
||||||
once
|
|
||||||
create Result
|
|
||||||
end
|
|
||||||
|
|
||||||
urlencode (s: READABLE_STRING_32): READABLE_STRING_8
|
|
||||||
-- URL encode `s'
|
|
||||||
do
|
|
||||||
Result := url_encoder.encoded_string (s)
|
|
||||||
end
|
|
||||||
|
|
||||||
urldecode (s: READABLE_STRING_8): READABLE_STRING_32
|
|
||||||
-- URL decode `s'
|
|
||||||
do
|
|
||||||
Result := url_encoder.decoded_string (s)
|
|
||||||
end
|
|
||||||
|
|
||||||
stripslashes (s: STRING): STRING
|
|
||||||
do
|
|
||||||
Result := s.string
|
|
||||||
Result.replace_substring_all ("\%"", "%"")
|
|
||||||
Result.replace_substring_all ("\'", "'")
|
|
||||||
Result.replace_substring_all ("\/", "/")
|
|
||||||
Result.replace_substring_all ("\\", "\")
|
|
||||||
end
|
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2016, 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
|
||||||
|
|||||||
@@ -142,16 +142,16 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
add_query_parameter (k: READABLE_STRING_32; v: READABLE_STRING_32)
|
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, k)
|
query_parameters.force (v.to_string_32, k.to_string_32)
|
||||||
end
|
end
|
||||||
|
|
||||||
add_form_parameter (k: READABLE_STRING_32; v: READABLE_STRING_32)
|
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, k)
|
form_parameters.force (v.to_string_32, k.to_string_32)
|
||||||
end
|
end
|
||||||
|
|
||||||
set_credentials_required (b: BOOLEAN)
|
set_credentials_required (b: BOOLEAN)
|
||||||
@@ -236,18 +236,62 @@ feature -- Status setting
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature -- URL helpers
|
||||||
|
|
||||||
|
append_query_parameters_to_url (a_url: STRING)
|
||||||
|
-- Append parameters `a_parameters' to `a_url'
|
||||||
|
require
|
||||||
|
a_url_attached: a_url /= Void
|
||||||
|
local
|
||||||
|
l_first_param: BOOLEAN
|
||||||
|
do
|
||||||
|
if
|
||||||
|
attached query_parameters as l_query_parameters and then
|
||||||
|
not l_query_parameters.is_empty
|
||||||
|
then
|
||||||
|
if a_url.index_of ('?', 1) > 0 then
|
||||||
|
l_first_param := False
|
||||||
|
elseif a_url.index_of ('&', 1) > 0 then
|
||||||
|
l_first_param := False
|
||||||
|
else
|
||||||
|
l_first_param := True
|
||||||
|
end
|
||||||
|
|
||||||
|
across
|
||||||
|
query_parameters as ic
|
||||||
|
loop
|
||||||
|
if l_first_param then
|
||||||
|
a_url.append_character ('?')
|
||||||
|
else
|
||||||
|
a_url.append_character ('&')
|
||||||
|
end
|
||||||
|
l_first_param := False
|
||||||
|
uri_percent_encoder.append_query_name_encoded_string_to (ic.key, a_url)
|
||||||
|
a_url.append_character ('=')
|
||||||
|
uri_percent_encoder.append_query_value_encoded_string_to (ic.item, a_url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Conversion helpers
|
feature -- Conversion helpers
|
||||||
|
|
||||||
query_parameters_to_url_encoded_string: STRING_8
|
query_parameters_to_url_encoded_string: STRING_8
|
||||||
-- `query_parameters' as url-encoded string.
|
-- `query_parameters' as url-encoded string.
|
||||||
do
|
do
|
||||||
Result := parameters_to_url_encoded_string (query_parameters)
|
Result := parameters_to_uri_percent_encoded_string (query_parameters)
|
||||||
|
end
|
||||||
|
|
||||||
|
form_parameters_to_x_www_form_url_encoded_string: STRING_8
|
||||||
|
-- `form_parameters' as x-www-form-urlencoded string.
|
||||||
|
do
|
||||||
|
Result := parameters_to_x_www_form_urlencoded_string (form_parameters)
|
||||||
end
|
end
|
||||||
|
|
||||||
form_parameters_to_url_encoded_string: STRING_8
|
form_parameters_to_url_encoded_string: STRING_8
|
||||||
-- `form_parameters' as url-encoded string.
|
-- `form_parameters' as url-encoded string.
|
||||||
|
obsolete "Use form_parameters_to_x_www_form_url_encoded_string [2017-05-31]"
|
||||||
do
|
do
|
||||||
Result := parameters_to_url_encoded_string (form_parameters)
|
Result := form_parameters_to_x_www_form_url_encoded_string
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
feature {NONE} -- Implementation
|
||||||
@@ -271,6 +315,52 @@ feature {NONE} -- Implementation
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
parameters_to_uri_percent_encoded_string (ht: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_32]): STRING_8
|
||||||
|
-- Build query urlencoded string using parameters from `ht'.
|
||||||
|
do
|
||||||
|
create Result.make (64)
|
||||||
|
across
|
||||||
|
ht as ic
|
||||||
|
loop
|
||||||
|
if not Result.is_empty then
|
||||||
|
Result.append_character ('&')
|
||||||
|
end
|
||||||
|
uri_percent_encoder.append_query_name_encoded_string_to (ic.key, Result)
|
||||||
|
Result.append_character ('=')
|
||||||
|
uri_percent_encoder.append_query_value_encoded_string_to (ic.item, Result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
parameters_to_x_www_form_urlencoded_string (ht: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_32]): STRING_8
|
||||||
|
-- Build x-www-form-urlencoded string using parameters from `ht'.
|
||||||
|
do
|
||||||
|
create Result.make (64)
|
||||||
|
from
|
||||||
|
ht.start
|
||||||
|
until
|
||||||
|
ht.after
|
||||||
|
loop
|
||||||
|
if not Result.is_empty then
|
||||||
|
Result.append_character ('&')
|
||||||
|
end
|
||||||
|
Result.append (x_www_form_url_encoder.encoded_string (ht.key_for_iteration))
|
||||||
|
Result.append_character ('=')
|
||||||
|
Result.append (x_www_form_url_encoder.encoded_string (ht.item_for_iteration))
|
||||||
|
ht.forth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
url_encoder: URL_ENCODER
|
url_encoder: URL_ENCODER
|
||||||
-- Shared URL encoder.
|
-- Shared URL encoder.
|
||||||
once
|
once
|
||||||
@@ -278,7 +368,7 @@ feature {NONE} -- Implementation
|
|||||||
end
|
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
|
||||||
|
|||||||
@@ -60,28 +60,10 @@ feature -- Access
|
|||||||
|
|
||||||
url (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): STRING_8
|
url (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): STRING_8
|
||||||
-- Url computed from Current and `ctx' data.
|
-- Url computed from Current and `ctx' data.
|
||||||
local
|
|
||||||
s: STRING_8
|
|
||||||
url_encoder: URL_ENCODER
|
|
||||||
do
|
do
|
||||||
Result := base_url + a_path
|
Result := base_url + a_path
|
||||||
if ctx /= Void then
|
if ctx /= Void then
|
||||||
create s.make_empty
|
ctx.append_query_parameters_to_url (Result)
|
||||||
create url_encoder
|
|
||||||
across
|
|
||||||
ctx.query_parameters as q
|
|
||||||
loop
|
|
||||||
if not s.is_empty then
|
|
||||||
s.append_character ('&')
|
|
||||||
end
|
|
||||||
s.append (url_encoder.encoded_string (q.key))
|
|
||||||
s.append_character ('=')
|
|
||||||
s.append (url_encoder.encoded_string (q.item))
|
|
||||||
end
|
|
||||||
if not s.is_empty then
|
|
||||||
Result.append_character ('?')
|
|
||||||
Result.append (s)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -420,7 +402,7 @@ feature -- Element change
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2016, 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
|
||||||
|
|||||||
@@ -0,0 +1,628 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Component to handle percent encoding
|
||||||
|
|
||||||
|
WARNING: THIS IS A COPY FROM $ISE_LIBRARY/library/text/uri library.
|
||||||
|
In the future, http_client will use directly the `uri` library.
|
||||||
|
]"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
EIS: "name=Percent-encoding", "protocol=URI", "src=http://en.wikipedia.org/wiki/Percent-encoding"
|
||||||
|
|
||||||
|
class
|
||||||
|
URI_PERCENT_ENCODER
|
||||||
|
|
||||||
|
feature -- Percent encoding
|
||||||
|
|
||||||
|
append_percent_encoded_string_to (s: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||||
|
-- Append `s' as percent-encoded value to `a_result'
|
||||||
|
local
|
||||||
|
i,n: INTEGER
|
||||||
|
do
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := s.count
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
append_encoded_character_code_to (s.code (i), a_result)
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
append_query_name_encoded_string_to (s: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||||
|
-- Append `s' as encoded for URI query name to `a_result'
|
||||||
|
local
|
||||||
|
i,n: INTEGER
|
||||||
|
do
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := s.count
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
append_query_name_encoded_character_code_to (s.code (i), a_result)
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
append_query_value_encoded_string_to (s: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||||
|
-- Append `s' as encoded for URI query value to `a_result'.
|
||||||
|
local
|
||||||
|
i,n: INTEGER
|
||||||
|
do
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := s.count
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
append_query_value_encoded_character_code_to (s.code (i), a_result)
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
append_path_segment_encoded_string_to (s: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||||
|
-- Append `a_string' as encoded for URI path segment to `a_result'
|
||||||
|
local
|
||||||
|
i,n: INTEGER
|
||||||
|
do
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := s.count
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
append_path_segment_encoded_character_code_to (s.code (i), a_result)
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
append_www_form_url_encoded_string_to (s: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||||
|
-- Append `a_string' as www-form-urlencoded value to `a_result'.
|
||||||
|
-- The main difference with `append_percent_encoded_string_to` is the encoding of space using '+'.
|
||||||
|
local
|
||||||
|
i,n: INTEGER
|
||||||
|
do
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := s.count
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
inspect s.code (i)
|
||||||
|
when 32 then -- space: 32 ' '
|
||||||
|
a_result.append_code (43) -- 43 '+'
|
||||||
|
else
|
||||||
|
append_encoded_character_code_to (s.code (i), a_result)
|
||||||
|
end
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- URI building helpers
|
||||||
|
|
||||||
|
append_encoded_character_code_to (c: NATURAL_32; a_result: STRING_GENERAL)
|
||||||
|
-- Append character code `c' as query name encoded content into `a_result'.
|
||||||
|
do
|
||||||
|
if
|
||||||
|
--| unreserved ALPHA / DIGIT
|
||||||
|
(48 <= c and c <= 57) -- DIGIT: 0 .. 9
|
||||||
|
or (65 <= c and c <= 90) -- ALPHA: A .. Z
|
||||||
|
or (97 <= c and c <= 122) -- ALPHA: a .. z
|
||||||
|
then
|
||||||
|
a_result.append_code (c)
|
||||||
|
else
|
||||||
|
inspect c
|
||||||
|
when
|
||||||
|
45, 46, 95, 126 -- unreserved characters: -._~
|
||||||
|
then
|
||||||
|
a_result.append_code (c)
|
||||||
|
when
|
||||||
|
58, 64, -- reserved =+ gen-delims: : @
|
||||||
|
33, 36, 38, 39, 40, 41, 42, -- reserved =+ sub-delims: ! $ & ' ( ) *
|
||||||
|
43, 44, 59, 61, -- reserved = sub-delims: + , ; =
|
||||||
|
37 -- percent encoding: %
|
||||||
|
then
|
||||||
|
append_percent_encoded_character_code_to (c, a_result)
|
||||||
|
else
|
||||||
|
append_percent_encoded_character_code_to (c, a_result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
append_query_name_encoded_character_code_to (c: NATURAL_32; a_result: STRING_GENERAL)
|
||||||
|
-- Append character code `a_code' as query name encoded content into `a_result'.
|
||||||
|
do
|
||||||
|
inspect c
|
||||||
|
when 61 then -- equal sign: =
|
||||||
|
append_percent_encoded_character_code_to (c, a_result)
|
||||||
|
else
|
||||||
|
append_query_value_encoded_character_code_to (c, a_result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
append_query_value_encoded_character_code_to (c: NATURAL_32; a_result: STRING_GENERAL)
|
||||||
|
-- Append character code `a_code' as query value encoded content into `a_result'.
|
||||||
|
do
|
||||||
|
inspect c
|
||||||
|
when 32 then -- Space
|
||||||
|
a_result.append_code (43) -- 43 '+'
|
||||||
|
when
|
||||||
|
39, -- '
|
||||||
|
58, 64, -- reserved =+ gen-delims: : @
|
||||||
|
33, 36, 40, 41, 42, -- reserved =+ sub-delims: ! $ ( ) *
|
||||||
|
44, 59, 61 -- reserved = sub-delims: , ; =
|
||||||
|
then
|
||||||
|
a_result.append_code (c)
|
||||||
|
when
|
||||||
|
47, -- slash: /
|
||||||
|
63 -- question mark ?
|
||||||
|
then
|
||||||
|
a_result.append_code (c)
|
||||||
|
else
|
||||||
|
append_encoded_character_code_to (c, a_result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
append_path_segment_encoded_character_code_to (c: NATURAL_32; a_result: STRING_GENERAL)
|
||||||
|
-- Append character code `a_code' as query name encoded content into `a_result'.
|
||||||
|
do
|
||||||
|
append_encoded_character_code_to (c, a_result)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Percent encoding: character
|
||||||
|
|
||||||
|
append_percent_encoded_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||||
|
-- Append character code `a_code' as percent-encoded content into `a_result'
|
||||||
|
do
|
||||||
|
if a_code > 0xFF then
|
||||||
|
-- Unicode
|
||||||
|
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||||
|
elseif a_code > 0x7F then
|
||||||
|
-- Extended ASCII
|
||||||
|
-- This requires percent-encoding on UTF-8 converted character.
|
||||||
|
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||||
|
else
|
||||||
|
-- ASCII
|
||||||
|
append_percent_encoded_ascii_character_code_to (a_code, a_result)
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
appended: a_result.count > old a_result.count
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation: character encoding
|
||||||
|
|
||||||
|
append_percent_encoded_ascii_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||||
|
-- Append extended ascii character code `a_code' as percent-encoded content into `a_result'
|
||||||
|
-- Note: it does not UTF-8 convert this extended ASCII.
|
||||||
|
require
|
||||||
|
is_extended_ascii: a_code <= 0xFF
|
||||||
|
local
|
||||||
|
c: INTEGER
|
||||||
|
do
|
||||||
|
if a_code > 0xFF then
|
||||||
|
-- Unicode
|
||||||
|
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||||
|
else
|
||||||
|
-- Extended ASCII
|
||||||
|
c := a_code.to_integer_32
|
||||||
|
a_result.append_code (37) -- 37 '%%'
|
||||||
|
a_result.append_code (hex_digit [c |>> 4])
|
||||||
|
a_result.append_code (hex_digit [c & 0xF])
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
appended: a_result.count > old a_result.count
|
||||||
|
end
|
||||||
|
|
||||||
|
append_percent_encoded_unicode_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||||
|
-- Append Unicode character code `a_code' as UTF-8 and percent-encoded content into `a_result'
|
||||||
|
-- Note: it does include UTF-8 conversion of extended ASCII and Unicode.
|
||||||
|
do
|
||||||
|
if a_code <= 0x7F then
|
||||||
|
-- 0xxxxxxx
|
||||||
|
append_percent_encoded_ascii_character_code_to (a_code, a_result)
|
||||||
|
elseif a_code <= 0x7FF then
|
||||||
|
-- 110xxxxx 10xxxxxx
|
||||||
|
append_percent_encoded_ascii_character_code_to ((a_code |>> 6) | 0xC0, a_result)
|
||||||
|
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||||
|
elseif a_code <= 0xFFFF then
|
||||||
|
-- 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
|
append_percent_encoded_ascii_character_code_to ((a_code |>> 12) | 0xE0, a_result)
|
||||||
|
append_percent_encoded_ascii_character_code_to (((a_code |>> 6) & 0x3F) | 0x80, a_result)
|
||||||
|
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||||
|
else
|
||||||
|
-- c <= 1FFFFF - there are no higher code points
|
||||||
|
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
append_percent_encoded_ascii_character_code_to ((a_code |>> 18) | 0xF0, a_result)
|
||||||
|
append_percent_encoded_ascii_character_code_to (((a_code |>> 12) & 0x3F) | 0x80, a_result)
|
||||||
|
append_percent_encoded_ascii_character_code_to (((a_code |>> 6) & 0x3F) | 0x80, a_result)
|
||||||
|
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
appended: a_result.count > old a_result.count
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Percent decoding
|
||||||
|
|
||||||
|
append_percent_decoded_string_to (v: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||||
|
-- Append to `a_result' a string equivalent to the percent-encoded string `v'
|
||||||
|
--| Note that is `a_result' is a STRING_8, any Unicode character will be kept as UTF-8
|
||||||
|
local
|
||||||
|
i,n: INTEGER
|
||||||
|
c: NATURAL_32
|
||||||
|
pr: CELL [INTEGER]
|
||||||
|
a_result_is_string_32: BOOLEAN
|
||||||
|
do
|
||||||
|
a_result_is_string_32 := attached {STRING_32} a_result
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
create pr.put (i)
|
||||||
|
n := v.count
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
c := v.code (i)
|
||||||
|
inspect c
|
||||||
|
when 43 then -- 43 '+'
|
||||||
|
-- Some implementation are replacing spaces with "+" instead of "%20"
|
||||||
|
a_result.append_code (32) -- 32 ' '
|
||||||
|
when 37 then -- 37 '%%'
|
||||||
|
-- An escaped character ?
|
||||||
|
if i = n then -- Error?
|
||||||
|
a_result.append_code (c)
|
||||||
|
else
|
||||||
|
if a_result_is_string_32 then
|
||||||
|
-- Convert UTF-8 to UTF-32
|
||||||
|
pr.replace (i)
|
||||||
|
c := next_percent_decoded_unicode_character_code (v, pr)
|
||||||
|
a_result.append_code (c)
|
||||||
|
i := pr.item
|
||||||
|
else
|
||||||
|
-- Keep UTF-8
|
||||||
|
pr.replace (i)
|
||||||
|
c := next_percent_decoded_character_code (v, pr)
|
||||||
|
a_result.append_code (c)
|
||||||
|
i := pr.item
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if c <= 0x7F then
|
||||||
|
a_result.append_code (c)
|
||||||
|
else
|
||||||
|
if a_result_is_string_32 then
|
||||||
|
a_result.append_code (c)
|
||||||
|
else
|
||||||
|
-- Keep the percent encoded char for non string 32.
|
||||||
|
append_percent_encoded_character_code_to (c, a_result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation: decoding
|
||||||
|
|
||||||
|
next_percent_decoded_character_code (v: READABLE_STRING_GENERAL; a_position: CELL [INTEGER]): NATURAL_32
|
||||||
|
-- Character decoded from string `v' starting from index `a_position.item'
|
||||||
|
-- note: it also updates `a_position.item' to indicate the new index position.
|
||||||
|
require
|
||||||
|
valid_start: a_position.item <= v.count
|
||||||
|
is_percent_char: v.code (a_position.item) = 37 -- 37 '%%'
|
||||||
|
local
|
||||||
|
c: NATURAL_32
|
||||||
|
i, n: INTEGER
|
||||||
|
not_a_digit: BOOLEAN
|
||||||
|
ascii_pos: NATURAL_32
|
||||||
|
ival: NATURAL_32
|
||||||
|
pos: INTEGER
|
||||||
|
c_is_digit: BOOLEAN
|
||||||
|
do
|
||||||
|
--| pos is index in stream of escape character ('%')
|
||||||
|
pos := a_position.item
|
||||||
|
c := v.code (pos + 1)
|
||||||
|
if c = 85 or c = 117 then -- 117 'u' 85 'U'
|
||||||
|
-- NOTE: this is not a standard, but it can occur, so use this for decoding only
|
||||||
|
-- An escaped Unicode (ucs2) value, from ECMA scripts
|
||||||
|
-- has the form: %u<n> where <n> is the UCS value
|
||||||
|
-- of the character (two byte integer, one to 4 chars
|
||||||
|
-- after escape sequence).
|
||||||
|
-- See: http://en.wikipedia.org/wiki/Percent-encoding#Non-standard_implementations
|
||||||
|
-- UTF-8 result can be 1 to 4 characters.
|
||||||
|
from
|
||||||
|
i := pos + 2
|
||||||
|
n := v.count
|
||||||
|
until
|
||||||
|
(i > n) or not_a_digit
|
||||||
|
loop
|
||||||
|
c := v.code (i)
|
||||||
|
c_is_digit := (48 <= c and c <= 57) -- DIGIT: 0 .. 9
|
||||||
|
if
|
||||||
|
c_is_digit
|
||||||
|
or (97 <= c and c <= 102) -- ALPHA: a..f
|
||||||
|
or (65 <= c and c <= 70) -- ALPHA: A..F
|
||||||
|
then
|
||||||
|
ival := ival * 16
|
||||||
|
if c_is_digit then
|
||||||
|
ival := ival + (c - 48) -- 48 '0'
|
||||||
|
else
|
||||||
|
if c > 70 then -- a..f
|
||||||
|
ival := ival + (c - 97) + 10 -- 97 'a'
|
||||||
|
else -- A..F
|
||||||
|
ival := ival + (c - 65) + 10 -- 65 'A'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i := i + 1
|
||||||
|
else
|
||||||
|
not_a_digit := True
|
||||||
|
i := i - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
a_position.replace (i)
|
||||||
|
Result := ival
|
||||||
|
else
|
||||||
|
-- ASCII char?
|
||||||
|
ascii_pos := hexadecimal_string_to_natural_32 (v.substring (pos + 1, pos + 2))
|
||||||
|
Result := ascii_pos
|
||||||
|
a_position.replace (pos + 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
next_percent_decoded_unicode_character_code (v: READABLE_STRING_GENERAL; a_position: CELL [INTEGER]): NATURAL_32
|
||||||
|
-- Next decoded character from `v' at position `a_position.item'
|
||||||
|
-- note: it also updates `a_position' to indicate the new index position.
|
||||||
|
require
|
||||||
|
valid_start: a_position.item <= v.count
|
||||||
|
is_percent_char: v.code (a_position.item) = 37 -- 37 '%%'
|
||||||
|
local
|
||||||
|
n, j: INTEGER
|
||||||
|
c: NATURAL_32
|
||||||
|
c1, c2, c3, c4: NATURAL_32
|
||||||
|
pr: CELL [INTEGER]
|
||||||
|
do
|
||||||
|
create pr.put (a_position.item)
|
||||||
|
c1 := next_percent_decoded_character_code (v, pr)
|
||||||
|
|
||||||
|
j := pr.item
|
||||||
|
n := v.count
|
||||||
|
|
||||||
|
Result := c1
|
||||||
|
a_position.replace (j)
|
||||||
|
|
||||||
|
if c1 <= 0x7F then
|
||||||
|
-- 0xxxxxxx
|
||||||
|
Result := c1
|
||||||
|
elseif c1 <= 0xDF then
|
||||||
|
-- 110xxxxx 10xxxxxx
|
||||||
|
if j + 2 <= n then
|
||||||
|
c := v.code (j + 1)
|
||||||
|
if c = 37 then -- 37 '%%'
|
||||||
|
pr.replace (j + 1)
|
||||||
|
c2 := next_percent_decoded_character_code (v, pr)
|
||||||
|
j := pr.item
|
||||||
|
Result := (
|
||||||
|
((c1 & 0x1F) |<< 6) |
|
||||||
|
( c2 & 0x3F )
|
||||||
|
)
|
||||||
|
a_position.replace (j)
|
||||||
|
else
|
||||||
|
-- Do not try to decode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif c1 <= 0xEF then
|
||||||
|
-- 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
|
if j + 2 <= n then
|
||||||
|
c := v.code (j + 1)
|
||||||
|
if c = 37 then -- 37 '%%'
|
||||||
|
pr.replace (j + 1)
|
||||||
|
c2 := next_percent_decoded_character_code (v, pr)
|
||||||
|
j := pr.item
|
||||||
|
if j + 2 <= n then
|
||||||
|
c := v.code (j + 1)
|
||||||
|
if c = 37 then -- 37 '%%'
|
||||||
|
pr.replace (j + 1)
|
||||||
|
c3 := next_percent_decoded_character_code (v, pr)
|
||||||
|
j := pr.item
|
||||||
|
|
||||||
|
Result := (
|
||||||
|
((c1 & 0xF) |<< 12) |
|
||||||
|
((c2 & 0x3F) |<< 6) |
|
||||||
|
( c3 & 0x3F )
|
||||||
|
)
|
||||||
|
a_position.replace (j)
|
||||||
|
else
|
||||||
|
-- Do not try to decode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Do not try to decode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif c1 <= 0xF7 then
|
||||||
|
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
|
||||||
|
if j + 2 <= n then
|
||||||
|
c := v.code (j + 1)
|
||||||
|
if c = 37 then -- 37 '%%'
|
||||||
|
pr.replace (j + 1)
|
||||||
|
c2 := next_percent_decoded_character_code (v, pr)
|
||||||
|
j := pr.item
|
||||||
|
if j + 2 <= n then
|
||||||
|
c := v.code (j + 1)
|
||||||
|
if c = 37 then -- 37 '%%'
|
||||||
|
pr.replace (j + 1)
|
||||||
|
c3 := next_percent_decoded_character_code (v, pr)
|
||||||
|
j := pr.item
|
||||||
|
if j + 2 <= n then
|
||||||
|
c := v.code (j + 1)
|
||||||
|
if c = 37 then -- 37 '%%'
|
||||||
|
pr.replace (j + 1)
|
||||||
|
c4 := next_percent_decoded_character_code (v, pr)
|
||||||
|
j := pr.item
|
||||||
|
|
||||||
|
a_position.replace (j)
|
||||||
|
|
||||||
|
Result := (
|
||||||
|
((c1 & 0x7) |<< 18 ) |
|
||||||
|
((c2 & 0x3F) |<< 12) |
|
||||||
|
((c3 & 0x3F) |<< 6) |
|
||||||
|
( c4 & 0x3F )
|
||||||
|
)
|
||||||
|
else
|
||||||
|
-- Do not try to decode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Do not try to decode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- Do not try to decode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result := c1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- RFC and characters
|
||||||
|
|
||||||
|
is_hexa_decimal_character (c: CHARACTER_32): BOOLEAN
|
||||||
|
-- Is hexadecimal character ?
|
||||||
|
do
|
||||||
|
Result := ('a' <= c and c <= 'f') or ('A' <= c and c <= 'F') -- HEXA
|
||||||
|
or ('0' <= c and c <= '9') -- DIGIT
|
||||||
|
end
|
||||||
|
|
||||||
|
is_alpha_or_digit_character (c: CHARACTER_32): BOOLEAN
|
||||||
|
-- Is ALPHA or DIGIT character ?
|
||||||
|
do
|
||||||
|
Result := ('a' <= c and c <= 'z') or ('A' <= c and c <= 'Z') -- ALPHA
|
||||||
|
or ('0' <= c and c <= '9') -- DIGIT
|
||||||
|
end
|
||||||
|
|
||||||
|
is_alpha_character (c: CHARACTER_32): BOOLEAN
|
||||||
|
-- Is ALPHA character ?
|
||||||
|
do
|
||||||
|
Result := ('a' <= c and c <= 'z') or ('A' <= c and c <= 'Z')
|
||||||
|
end
|
||||||
|
|
||||||
|
is_digit_character (c: CHARACTER_32): BOOLEAN
|
||||||
|
-- Is DIGIT character ?
|
||||||
|
do
|
||||||
|
Result := ('0' <= c and c <= '9')
|
||||||
|
end
|
||||||
|
|
||||||
|
is_unreserved_character (c: CHARACTER_32): BOOLEAN
|
||||||
|
-- unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||||
|
do
|
||||||
|
if
|
||||||
|
('a' <= c and c <= 'z') -- ALPHA
|
||||||
|
or ('A' <= c and c <= 'Z') -- ALPHA
|
||||||
|
or ('0' <= c and c <= '9') -- DIGIT
|
||||||
|
then
|
||||||
|
Result := True
|
||||||
|
else
|
||||||
|
inspect c
|
||||||
|
when '-', '_', '.', '~' then -- unreserved
|
||||||
|
Result := True
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
is_reserved_character (c: CHARACTER_32): BOOLEAN
|
||||||
|
-- reserved = gen-delims / sub-delims
|
||||||
|
do
|
||||||
|
Result := is_gen_delims_character (c) or is_sub_delims_character (c)
|
||||||
|
end
|
||||||
|
|
||||||
|
is_gen_delims_character (c: CHARACTER_32): BOOLEAN
|
||||||
|
-- gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
|
||||||
|
do
|
||||||
|
inspect c
|
||||||
|
when ':' , '/', '?' , '#' , '[' , ']' , '@' then
|
||||||
|
Result := True
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
is_sub_delims_character (c: CHARACTER_32): BOOLEAN
|
||||||
|
-- sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||||
|
-- / "*" / "+" / "," / ";" / "="
|
||||||
|
do
|
||||||
|
inspect c
|
||||||
|
when '!' , '$' , '&' , '%'' , '(' , ')' , '*' , '+' , ',' , ';' , '=' then -- sub-delims
|
||||||
|
Result := True
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
hex_digit: SPECIAL [NATURAL_32]
|
||||||
|
-- Hexadecimal digits.
|
||||||
|
once
|
||||||
|
create Result.make_filled (0, 16)
|
||||||
|
Result [0] := {NATURAL_32} 48 -- 48 '0'
|
||||||
|
Result [1] := {NATURAL_32} 49 -- 49 '1'
|
||||||
|
Result [2] := {NATURAL_32} 50 -- 50 '2'
|
||||||
|
Result [3] := {NATURAL_32} 51 -- 51 '3'
|
||||||
|
Result [4] := {NATURAL_32} 52 -- 52 '4'
|
||||||
|
Result [5] := {NATURAL_32} 53 -- 53 '5'
|
||||||
|
Result [6] := {NATURAL_32} 54 -- 54 '6'
|
||||||
|
Result [7] := {NATURAL_32} 55 -- 55 '7'
|
||||||
|
Result [8] := {NATURAL_32} 56 -- 56 '8'
|
||||||
|
Result [9] := {NATURAL_32} 57 -- 57 '9'
|
||||||
|
Result [10] := {NATURAL_32} 65 -- 65 'A'
|
||||||
|
Result [11] := {NATURAL_32} 66 -- 66 'B'
|
||||||
|
Result [12] := {NATURAL_32} 67 -- 67 'C'
|
||||||
|
Result [13] := {NATURAL_32} 68 -- 68 'D'
|
||||||
|
Result [14] := {NATURAL_32} 69 -- 69 'E'
|
||||||
|
Result [15] := {NATURAL_32} 70 -- 70 'F'
|
||||||
|
end
|
||||||
|
|
||||||
|
is_hexa_decimal (a_string: READABLE_STRING_GENERAL): BOOLEAN
|
||||||
|
-- Is `a_string' a valid hexadecimal sequence?
|
||||||
|
local
|
||||||
|
l_convertor: like ctoi_convertor
|
||||||
|
do
|
||||||
|
l_convertor := ctoi_convertor
|
||||||
|
l_convertor.parse_string_with_type (a_string, {NUMERIC_INFORMATION}.type_natural_32)
|
||||||
|
Result := l_convertor.is_integral_integer
|
||||||
|
end
|
||||||
|
|
||||||
|
hexadecimal_string_to_natural_32 (a_hex_string: READABLE_STRING_GENERAL): NATURAL_32
|
||||||
|
-- Convert hexadecimal value `a_hex_string' to its corresponding NATURAL_32 value.
|
||||||
|
require
|
||||||
|
is_hexa: is_hexa_decimal (a_hex_string)
|
||||||
|
local
|
||||||
|
l_convertor: like ctoi_convertor
|
||||||
|
do
|
||||||
|
l_convertor := ctoi_convertor
|
||||||
|
l_convertor.parse_string_with_type (a_hex_string, {NUMERIC_INFORMATION}.type_no_limitation)
|
||||||
|
Result := l_convertor.parsed_natural_32
|
||||||
|
end
|
||||||
|
|
||||||
|
ctoi_convertor: HEXADECIMAL_STRING_TO_INTEGER_CONVERTER
|
||||||
|
-- Converter used to convert string to integer or natural.
|
||||||
|
once
|
||||||
|
create Result.make
|
||||||
|
Result.set_leading_separators_acceptable (False)
|
||||||
|
Result.set_trailing_separators_acceptable (False)
|
||||||
|
ensure
|
||||||
|
ctoi_convertor_not_void: Result /= Void
|
||||||
|
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
|
||||||
@@ -82,9 +82,6 @@ feature -- Execution
|
|||||||
|
|
||||||
--| URL
|
--| URL
|
||||||
l_url := url
|
l_url := url
|
||||||
if ctx /= Void then
|
|
||||||
append_parameters_to_url (ctx.query_parameters, l_url)
|
|
||||||
end
|
|
||||||
|
|
||||||
if session.is_header_sent_verbose then
|
if session.is_header_sent_verbose then
|
||||||
io.error.put_string ("> Sending:%N")
|
io.error.put_string ("> Sending:%N")
|
||||||
@@ -171,7 +168,7 @@ feature -- Execution
|
|||||||
then
|
then
|
||||||
if l_ct.starts_with ("application/x-www-form-urlencoded") then
|
if l_ct.starts_with ("application/x-www-form-urlencoded") then
|
||||||
-- Content-Type is already application/x-www-form-urlencoded
|
-- Content-Type is already application/x-www-form-urlencoded
|
||||||
l_upload_data := ctx.form_parameters_to_url_encoded_string
|
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
||||||
elseif l_ct.starts_with ("multipart/form-data") then
|
elseif l_ct.starts_with ("multipart/form-data") then
|
||||||
l_use_curl_form := True
|
l_use_curl_form := True
|
||||||
else
|
else
|
||||||
@@ -179,7 +176,7 @@ feature -- Execution
|
|||||||
l_use_curl_form := True
|
l_use_curl_form := True
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
l_upload_data := ctx.form_parameters_to_url_encoded_string
|
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
l_use_curl_form := True
|
l_use_curl_form := True
|
||||||
@@ -199,6 +196,14 @@ feature -- Execution
|
|||||||
)
|
)
|
||||||
l_form_data.forth
|
l_form_data.forth
|
||||||
end
|
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
|
l_last.release_item
|
||||||
curl_easy.setopt_form (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httppost, l_form)
|
curl_easy.setopt_form (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httppost, l_form)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ feature -- Custom
|
|||||||
local
|
local
|
||||||
req: HTTP_CLIENT_REQUEST
|
req: HTTP_CLIENT_REQUEST
|
||||||
do
|
do
|
||||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, a_method, Current, ctx)
|
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (url (a_path, ctx), a_method, Current, ctx)
|
||||||
Result := req.response
|
Result := req.response
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ feature {NONE} -- Implementation
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, a_method, Current, ctx)
|
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (url (a_path, ctx), a_method, Current, ctx)
|
||||||
Result := req.response
|
Result := req.response
|
||||||
|
|
||||||
if f /= Void then
|
if f /= Void then
|
||||||
@@ -176,7 +176,7 @@ feature {LIBCURL_HTTP_CLIENT_REQUEST} -- Curl implementation
|
|||||||
|
|
||||||
|
|
||||||
;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
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ feature -- Access
|
|||||||
end
|
end
|
||||||
|
|
||||||
create l_request_uri.make_from_string (l_uri.path)
|
create l_request_uri.make_from_string (l_uri.path)
|
||||||
if attached l_uri.query as l_query then
|
if attached l_uri.query as l_query and then not l_query.is_empty then
|
||||||
l_request_uri.append_character ('?')
|
l_request_uri.append_character ('?')
|
||||||
l_request_uri.append (l_query)
|
l_request_uri.append (l_query)
|
||||||
end
|
end
|
||||||
@@ -198,7 +198,7 @@ feature -- Access
|
|||||||
attached headers.item ("Content-Type") as l_ct
|
attached headers.item ("Content-Type") as l_ct
|
||||||
then
|
then
|
||||||
if l_ct.starts_with ("application/x-www-form-urlencoded") then
|
if l_ct.starts_with ("application/x-www-form-urlencoded") then
|
||||||
l_upload_data := ctx.form_parameters_to_url_encoded_string
|
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
||||||
elseif l_ct.starts_with ("multipart/form-data") then
|
elseif l_ct.starts_with ("multipart/form-data") then
|
||||||
-- create form using multipart/form-data encoding
|
-- create form using multipart/form-data encoding
|
||||||
l_boundary := new_mime_boundary (l_form_data)
|
l_boundary := new_mime_boundary (l_form_data)
|
||||||
@@ -208,12 +208,12 @@ feature -- Access
|
|||||||
-- not supported !
|
-- not supported !
|
||||||
-- Send as form-urlencoded
|
-- Send as form-urlencoded
|
||||||
headers.extend ("application/x-www-form-urlencoded", "Content-Type")
|
headers.extend ("application/x-www-form-urlencoded", "Content-Type")
|
||||||
l_upload_data := ctx.form_parameters_to_url_encoded_string
|
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- Send as form-urlencoded
|
-- Send as form-urlencoded
|
||||||
headers.extend ("application/x-www-form-urlencoded", "Content-Type")
|
headers.extend ("application/x-www-form-urlencoded", "Content-Type")
|
||||||
l_upload_data := ctx.form_parameters_to_url_encoded_string
|
l_upload_data := ctx.form_parameters_to_x_www_form_url_encoded_string
|
||||||
end
|
end
|
||||||
headers.extend (l_upload_data.count.out, "Content-Length")
|
headers.extend (l_upload_data.count.out, "Content-Length")
|
||||||
if l_is_chunked_transfer_encoding then
|
if l_is_chunked_transfer_encoding then
|
||||||
@@ -246,7 +246,7 @@ feature -- Access
|
|||||||
elseif l_upload_filename /= Void then
|
elseif l_upload_filename /= Void then
|
||||||
check ctx.has_upload_filename end
|
check ctx.has_upload_filename 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.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.extend (l_upload_file.count.out, "Content-Length")
|
||||||
end
|
end
|
||||||
@@ -495,6 +495,7 @@ feature {NONE} -- Helpers
|
|||||||
across
|
across
|
||||||
a_form_parameters as ic
|
a_form_parameters as ic
|
||||||
loop
|
loop
|
||||||
|
Result.append ("--")
|
||||||
Result.append (a_mime_boundary)
|
Result.append (a_mime_boundary)
|
||||||
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=")
|
||||||
@@ -519,7 +520,7 @@ feature {NONE} -- Helpers
|
|||||||
else
|
else
|
||||||
l_mime_type := "application/octet-stream"
|
l_mime_type := "application/octet-stream"
|
||||||
end
|
end
|
||||||
|
Result.append ("--")
|
||||||
Result.append (a_mime_boundary)
|
Result.append (a_mime_boundary)
|
||||||
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=%"")
|
||||||
@@ -542,6 +543,7 @@ feature {NONE} -- Helpers
|
|||||||
end
|
end
|
||||||
Result.append (http_end_of_header_line)
|
Result.append (http_end_of_header_line)
|
||||||
end
|
end
|
||||||
|
Result.append ("--")
|
||||||
Result.append (a_mime_boundary)
|
Result.append (a_mime_boundary)
|
||||||
Result.append ("--") --| end
|
Result.append ("--") --| end
|
||||||
end
|
end
|
||||||
@@ -907,7 +909,7 @@ feature {NONE} -- Helpers
|
|||||||
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
|
||||||
ran.forth
|
ran.forth
|
||||||
n := (20 * ran.real_item).truncated_to_integer
|
n := (10 * ran.real_item).truncated_to_integer
|
||||||
create Result.make_filled ('-', 3 + n)
|
create Result.make_filled ('-', 3 + n)
|
||||||
s := "_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
s := "_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
from
|
from
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ feature -- Custom
|
|||||||
local
|
local
|
||||||
req: HTTP_CLIENT_REQUEST
|
req: HTTP_CLIENT_REQUEST
|
||||||
do
|
do
|
||||||
create {NET_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, a_method, Current, ctx)
|
create {NET_HTTP_CLIENT_REQUEST} req.make (url (a_path, ctx), a_method, Current, ctx)
|
||||||
Result := req.response
|
Result := req.response
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -167,12 +167,12 @@ feature {NONE} -- Implementation
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
create {NET_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, a_method, Current, ctx)
|
create {NET_HTTP_CLIENT_REQUEST} req.make (url (a_path, ctx), a_method, Current, ctx)
|
||||||
Result := req.response
|
Result := req.response
|
||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2016, 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
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ feature -- Custom
|
|||||||
|
|
||||||
custom (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
custom (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
|
||||||
do
|
do
|
||||||
create Result.make (base_url + a_path)
|
create Result.make (url (a_path, ctx))
|
||||||
end
|
end
|
||||||
|
|
||||||
custom_with_upload_data (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: READABLE_STRING_8): HTTP_CLIENT_RESPONSE
|
custom_with_upload_data (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: READABLE_STRING_8): HTTP_CLIENT_RESPONSE
|
||||||
@@ -98,7 +98,7 @@ feature -- Status report
|
|||||||
-- Is interface usable?
|
-- Is interface usable?
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ feature -- Tests
|
|||||||
test_post_with_form_data
|
test_post_with_form_data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
libcurl_test_post_with_uncommon_form_data
|
||||||
|
do
|
||||||
|
test_post_with_uncommon_form_data
|
||||||
|
end
|
||||||
|
|
||||||
libcurl_test_post_with_file
|
libcurl_test_post_with_file
|
||||||
do
|
do
|
||||||
test_post_with_file
|
test_post_with_file
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ feature -- Tests
|
|||||||
test_post_with_form_data
|
test_post_with_form_data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
net_test_post_with_uncommon_form_data
|
||||||
|
do
|
||||||
|
test_post_with_uncommon_form_data
|
||||||
|
end
|
||||||
|
|
||||||
net_test_post_with_file
|
net_test_post_with_file
|
||||||
do
|
do
|
||||||
test_post_with_file
|
test_post_with_file
|
||||||
@@ -69,4 +74,9 @@ feature -- Tests
|
|||||||
test_post_with_file_using_chunked_transfer_encoding
|
test_post_with_file_using_chunked_transfer_encoding
|
||||||
end
|
end
|
||||||
|
|
||||||
|
net_test_get_with_query_parameters
|
||||||
|
do
|
||||||
|
test_get_with_query_parameters
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
note
|
note
|
||||||
description: "[
|
description: "[
|
||||||
Eiffel tests that can be executed by testing tool.
|
Eiffel tests that can be executed by testing tool.
|
||||||
]"
|
]"
|
||||||
@@ -21,7 +21,10 @@ feature -- Initialization
|
|||||||
on_prepare
|
on_prepare
|
||||||
do
|
do
|
||||||
Precursor
|
Precursor
|
||||||
global_requestbin_path := new_requestbin_path
|
global_requestbin_path := "/s0jkhhs0"
|
||||||
|
if global_requestbin_path = Void then
|
||||||
|
global_requestbin_path := new_requestbin_path
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Factory
|
feature -- Factory
|
||||||
@@ -49,6 +52,9 @@ feature -- Requestbin
|
|||||||
i := l_content.substring_index ("%"name%":", 1)
|
i := l_content.substring_index ("%"name%":", 1)
|
||||||
if i > 0 then
|
if i > 0 then
|
||||||
j := l_content.index_of (',', i + 1)
|
j := l_content.index_of (',', i + 1)
|
||||||
|
if j = 0 then
|
||||||
|
j := l_content.index_of ('}', i + 1)
|
||||||
|
end
|
||||||
if j > 0 then
|
if j > 0 then
|
||||||
Result := l_content.substring (i + 7, j - 1)
|
Result := l_content.substring (i + 7, j - 1)
|
||||||
Result.adjust
|
Result.adjust
|
||||||
@@ -61,6 +67,7 @@ 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")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -108,8 +115,55 @@ feature -- Factory
|
|||||||
-- check requestbin to ensure the form parameters are correctly received
|
-- check requestbin to ensure the form parameters are correctly received
|
||||||
sess := new_session ("http://requestb.in")
|
sess := new_session ("http://requestb.in")
|
||||||
create l_ctx.make
|
create l_ctx.make
|
||||||
l_ctx.form_parameters.extend ("First Value", "First Key")
|
l_ctx.add_form_parameter ("First Key", "First Value")
|
||||||
l_ctx.form_parameters.extend ("Second Value", "Second Key")
|
l_ctx.add_form_parameter ("Second Key", "Second Value")
|
||||||
|
l_ctx.add_form_parameter ("unicode", {STRING_32} "Hello / 你好 !")
|
||||||
|
l_ctx.add_form_parameter ({STRING_32} "Field 你好 !", "How are you?")
|
||||||
|
create h.make_empty
|
||||||
|
if
|
||||||
|
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
|
||||||
|
|
||||||
|
test_post_with_uncommon_form_data
|
||||||
|
local
|
||||||
|
sess: HTTP_CLIENT_SESSION
|
||||||
|
h: STRING_8
|
||||||
|
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||||
|
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_session ("http://requestb.in")
|
||||||
|
create l_ctx.make
|
||||||
|
|
||||||
|
l_ctx.add_form_parameter ("title", "Eiffel World!") -- space and !
|
||||||
|
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"))
|
||||||
|
|
||||||
create h.make_empty
|
create h.make_empty
|
||||||
if
|
if
|
||||||
attached sess.post (requestbin_path, l_ctx, "") as res and then
|
attached sess.post (requestbin_path, l_ctx, "") as res and then
|
||||||
@@ -143,7 +197,7 @@ feature -- Factory
|
|||||||
l_ctx.set_upload_filename ("test.txt")
|
l_ctx.set_upload_filename ("test.txt")
|
||||||
create h.make_empty
|
create h.make_empty
|
||||||
if
|
if
|
||||||
attached sess.post (requestbin_path, l_ctx, "") as res and then
|
attached sess.post (requestbin_path, l_ctx, Void) as res and then
|
||||||
attached res.headers as hds
|
attached res.headers as hds
|
||||||
then
|
then
|
||||||
across
|
across
|
||||||
@@ -202,7 +256,7 @@ feature -- Factory
|
|||||||
-- set filename to a local file
|
-- set filename to a local file
|
||||||
sess := new_session ("http://requestb.in")
|
sess := new_session ("http://requestb.in")
|
||||||
create l_ctx.make
|
create l_ctx.make
|
||||||
l_ctx.set_upload_data ("This is a test for http client.%N")
|
l_ctx.set_upload_data ("name=This is a test for http client.%N")
|
||||||
create h.make_empty
|
create h.make_empty
|
||||||
if
|
if
|
||||||
attached sess.put (requestbin_path, l_ctx, Void) as res and then
|
attached sess.put (requestbin_path, l_ctx, Void) as res and then
|
||||||
@@ -232,10 +286,12 @@ feature -- Factory
|
|||||||
-- check requestbin to ensure the file and form parameters are correctly received
|
-- check requestbin to ensure the file and form parameters are correctly received
|
||||||
-- set filename to a local file
|
-- set filename to a local file
|
||||||
sess := new_session ("http://requestb.in")
|
sess := new_session ("http://requestb.in")
|
||||||
|
-- sess := new_session ("http://localhost:9090")
|
||||||
create l_ctx.make
|
create l_ctx.make
|
||||||
l_ctx.set_upload_filename ("logo.jpg")
|
-- l_ctx.set_upload_filename ("logo.jpg")
|
||||||
l_ctx.form_parameters.extend ("First Value", "First Key")
|
l_ctx.set_upload_filename ("test.txt")
|
||||||
l_ctx.form_parameters.extend ("Second Value", "Second Key")
|
l_ctx.add_form_parameter ("First", "Value")
|
||||||
|
l_ctx.add_form_parameter ("Second", "and last value")
|
||||||
create h.make_empty
|
create h.make_empty
|
||||||
if
|
if
|
||||||
attached sess.post (requestbin_path, l_ctx, Void) as res and then
|
attached sess.post (requestbin_path, l_ctx, Void) as res and then
|
||||||
@@ -297,6 +353,7 @@ feature -- Factory
|
|||||||
sess := new_session ("http://google.com")
|
sess := new_session ("http://google.com")
|
||||||
create h.make_empty
|
create h.make_empty
|
||||||
if attached sess.get ("/", Void) as res and then attached res.headers as hds then
|
if attached sess.get ("/", Void) as res and then attached res.headers as hds then
|
||||||
|
assert("was redirected", res.redirections_count > 0)
|
||||||
across
|
across
|
||||||
hds as c
|
hds as c
|
||||||
loop
|
loop
|
||||||
@@ -328,6 +385,53 @@ feature -- Factory
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test_get_with_query_parameters
|
||||||
|
local
|
||||||
|
sess: HTTP_CLIENT_SESSION
|
||||||
|
h: STRING_8
|
||||||
|
l_ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||||
|
q: STRING
|
||||||
|
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
|
||||||
|
-- set filename to a local file
|
||||||
|
sess := new_session ("http://requestb.in")
|
||||||
|
create l_ctx.make
|
||||||
|
l_ctx.add_query_parameter ("?", "?first&arg")
|
||||||
|
l_ctx.add_query_parameter ("title", "Eiffel World!")
|
||||||
|
l_ctx.add_query_parameter ("path", "foo/bar")
|
||||||
|
l_ctx.add_query_parameter ("reserved", "+=&?")
|
||||||
|
l_ctx.add_query_parameter ("unreserved", ":!@'()*")
|
||||||
|
l_ctx.add_query_parameter ("unsafe", "%"[]{}")
|
||||||
|
l_ctx.add_query_parameter ("test", "!$&'()*")
|
||||||
|
l_ctx.add_query_parameter ("a&b", "a&b")
|
||||||
|
l_ctx.add_query_parameter ("lst[a][b]", "[abc][123]")
|
||||||
|
l_ctx.add_query_parameter ("foo(a,b)", "bar(1,2)*pi")
|
||||||
|
create q.make_empty
|
||||||
|
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
|
||||||
|
attached sess.get (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
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>/http_stream_socket_ext.e$</exclude>
|
<exclude>/http_stream_socket_ext.e$</exclude>
|
||||||
<condition>
|
<condition>
|
||||||
<version type="compiler" max="16.9.9.9124"/>
|
<version type="compiler" max="17.02"/>
|
||||||
</condition>
|
</condition>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<cluster name="disabled_ssl_network" location="$|no_ssl\" recursive="true">
|
<cluster name="disabled_ssl_network" location="$|no_ssl\" recursive="true">
|
||||||
@@ -114,6 +114,11 @@
|
|||||||
</condition>
|
</condition>
|
||||||
</cluster>
|
</cluster>
|
||||||
</cluster>
|
</cluster>
|
||||||
|
<cluster name="network_until_17_01" location=".\src\until_17_01\">
|
||||||
|
<condition>
|
||||||
|
<version type="compiler" min="16.9.9.9124" max="17.02"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
</target>
|
</target>
|
||||||
<target name="http_network_ssl" extends="http_network">
|
<target name="http_network_ssl" extends="http_network">
|
||||||
<variable name="ssl_enabled" value="true"/>
|
<variable name="ssl_enabled" value="true"/>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>/http_stream_socket_ext.e$</exclude>
|
<exclude>/http_stream_socket_ext.e$</exclude>
|
||||||
<condition>
|
<condition>
|
||||||
<version type="compiler" max="16.9.9.9124"/>
|
<version type="compiler" max="17.02"/>
|
||||||
</condition>
|
</condition>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<cluster name="disabled_ssl_network" location="$|no_ssl\" recursive="true">
|
<cluster name="disabled_ssl_network" location="$|no_ssl\" recursive="true">
|
||||||
@@ -114,6 +114,11 @@
|
|||||||
</condition>
|
</condition>
|
||||||
</cluster>
|
</cluster>
|
||||||
</cluster>
|
</cluster>
|
||||||
|
<cluster name="network_until_17_01" location=".\src\until_17_01\">
|
||||||
|
<condition>
|
||||||
|
<version type="compiler" min="16.9.9.9124" max="17.02"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
</target>
|
</target>
|
||||||
<target name="http_network_ssl" extends="http_network">
|
<target name="http_network_ssl" extends="http_network">
|
||||||
<variable name="ssl_enabled" value="true"/>
|
<variable name="ssl_enabled" value="true"/>
|
||||||
|
|||||||
@@ -36,13 +36,13 @@ feature -- Input
|
|||||||
-- Make result available in `last_character'.
|
-- Make result available in `last_character'.
|
||||||
-- No exception raised!
|
-- No exception raised!
|
||||||
do
|
do
|
||||||
read_to_managed_pointer_noexception (socket_buffer, 0, character_8_bytes)
|
read_to_managed_pointer_noexception (read_socket_buffer, 0, character_8_bytes)
|
||||||
if was_error then
|
if was_error then
|
||||||
-- Socket error already set.
|
-- Socket error already set.
|
||||||
elseif bytes_read /= character_8_bytes then
|
elseif bytes_read /= character_8_bytes then
|
||||||
socket_error := "Peer closed connection"
|
socket_error := "Peer closed connection"
|
||||||
else
|
else
|
||||||
last_character := socket_buffer.read_character (0)
|
last_character := read_socket_buffer.read_character (0)
|
||||||
socket_error := Void
|
socket_error := Void
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -208,8 +208,8 @@ feature -- Output
|
|||||||
put_character_noexception (c: CHARACTER)
|
put_character_noexception (c: CHARACTER)
|
||||||
-- Write character `c' to socket.
|
-- Write character `c' to socket.
|
||||||
do
|
do
|
||||||
socket_buffer.put_character (c, 0)
|
put_socket_buffer.put_character (c, 0)
|
||||||
put_managed_pointer_noexception (socket_buffer, 0, character_8_bytes)
|
put_managed_pointer_noexception (put_socket_buffer, 0, character_8_bytes)
|
||||||
end
|
end
|
||||||
|
|
||||||
put_string_8_noexception (s: READABLE_STRING_8)
|
put_string_8_noexception (s: READABLE_STRING_8)
|
||||||
@@ -244,7 +244,7 @@ feature -- Status report
|
|||||||
end
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2016, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software 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: "[
|
source: "[
|
||||||
Eiffel Software
|
Eiffel Software
|
||||||
|
|||||||
@@ -2,12 +2,20 @@ note
|
|||||||
description: "[
|
description: "[
|
||||||
Extension to HTTPD_STREAM_SOCKET to support backward compatibility.
|
Extension to HTTPD_STREAM_SOCKET to support backward compatibility.
|
||||||
|
|
||||||
TO BE REMOVED IN THE FUTURE, WHEN 16.05 IS OLD.
|
TO BE REMOVED IN THE FUTURE, When there is no need to support older compilers.
|
||||||
]"
|
]"
|
||||||
|
|
||||||
deferred class
|
deferred class
|
||||||
HTTP_STREAM_SOCKET_EXT
|
HTTP_STREAM_SOCKET_EXT
|
||||||
|
|
||||||
feature {NONE} -- No-Exception network operation
|
note
|
||||||
|
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -51,6 +51,20 @@ feature -- Access
|
|||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
|
socket_buffer: MANAGED_POINTER
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
read_socket_buffer: MANAGED_POINTER
|
||||||
|
do
|
||||||
|
Result := socket_buffer
|
||||||
|
end
|
||||||
|
|
||||||
|
put_socket_buffer: MANAGED_POINTER
|
||||||
|
do
|
||||||
|
Result := socket_buffer
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Socket Recv and Send timeout.
|
feature -- Socket Recv and Send timeout.
|
||||||
|
|
||||||
set_recv_timeout (a_timeout_seconds: INTEGER)
|
set_recv_timeout (a_timeout_seconds: INTEGER)
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Extension to HTTPD_STREAM_SOCKET to support backward compatibility.
|
||||||
|
|
||||||
|
TO BE REMOVED IN THE FUTURE, WHEN 17.01 IS OLD.
|
||||||
|
]"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
HTTP_STREAM_SOCKET_EXT
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
socket_buffer: MANAGED_POINTER
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
read_socket_buffer: MANAGED_POINTER
|
||||||
|
do
|
||||||
|
Result := socket_buffer
|
||||||
|
end
|
||||||
|
|
||||||
|
put_socket_buffer: MANAGED_POINTER
|
||||||
|
do
|
||||||
|
Result := socket_buffer
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- No-Exception network operation
|
||||||
|
|
||||||
|
end
|
||||||
47
library/text/encoder/src/x_www_form_url_encoder.e
Normal file
47
library/text/encoder/src/x_www_form_url_encoder.e
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {X_WWW_FORM_URL_ENCODER}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
X_WWW_FORM_URL_ENCODER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
URL_ENCODER
|
||||||
|
redefine
|
||||||
|
append_percent_encoded_ascii_character_code_to
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation: character encoding
|
||||||
|
|
||||||
|
append_percent_encoded_ascii_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||||
|
-- <Precursor>
|
||||||
|
-- Note: space is encoded with '+' for x-www-form-urlencoding.
|
||||||
|
do
|
||||||
|
inspect a_code
|
||||||
|
when
|
||||||
|
32 -- 32 ' '
|
||||||
|
then
|
||||||
|
a_result.append_code (43) -- 43 '+'
|
||||||
|
when
|
||||||
|
33, 39, -- ! '
|
||||||
|
40, 41, 42 -- ( ) *
|
||||||
|
then
|
||||||
|
a_result.append_code (a_code) -- Keep slash
|
||||||
|
else
|
||||||
|
Precursor (a_code, a_result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 2011-2017, 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
|
||||||
Reference in New Issue
Block a user