Added https support with Net implementation.
Added notion of default HTTP_CLIENT, to be able to build portable code among http client implementation.
This commit is contained in:
@@ -24,20 +24,60 @@
|
||||
<custom name="net_http_client_disabled" excluded_value="true"/>
|
||||
</condition>
|
||||
</library>
|
||||
<library name="net_ssl" location="$ISE_LIBRARY\unstable\library\network\socket\netssl\net_ssl-safe.ecf">
|
||||
<condition>
|
||||
<custom name="net_http_client_disabled" excluded_value="true"/>
|
||||
<custom name="netssl_http_client_enabled" value="true"/>
|
||||
</condition>
|
||||
</library>
|
||||
|
||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
|
||||
<cluster name="src" location=".\src\">
|
||||
<cluster name="spec_null" location="$|spec/null" recursive="true"/>
|
||||
<cluster name="spec_net" location="$|spec/socket" recursive="true">
|
||||
<cluster name="spec_net" location="$|spec/net">
|
||||
<condition>
|
||||
<custom name="net_http_client_disabled" excluded_value="true"/>
|
||||
</condition>
|
||||
<cluster name="net_ssl_disabled" location="$|no_ssl">
|
||||
<condition>
|
||||
<custom name="netssl_http_client_enabled" excluded_value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="net_ssl_enabled" location="$|ssl">
|
||||
<condition>
|
||||
<custom name="netssl_http_client_enabled" value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
</cluster>
|
||||
<cluster name="spec_libcurl" location="$|spec/libcurl" recursive="true">
|
||||
<condition>
|
||||
<custom name="libcurl_http_client_disabled" excluded_value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="default_null" location="$|default/null">
|
||||
<condition>
|
||||
<custom name="net_http_client_disabled" value="true"/>
|
||||
<custom name="libcurl_http_client_disabled" value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="default_net" location="$|default/net">
|
||||
<condition>
|
||||
<custom name="net_http_client_disabled" excluded_value="true"/>
|
||||
<custom name="libcurl_http_client_disabled" value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="default_libcurl" location="$|default/libcurl">
|
||||
<condition>
|
||||
<custom name="net_http_client_disabled" value="true"/>
|
||||
<custom name="libcurl_http_client_disabled" excluded_value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
<cluster name="default_libcurl_or_net" location="$|default/libcurl_or_net">
|
||||
<condition>
|
||||
<custom name="net_http_client_disabled" excluded_value="true"/>
|
||||
<custom name="libcurl_http_client_disabled" excluded_value="true"/>
|
||||
</condition>
|
||||
</cluster>
|
||||
</cluster>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
note
|
||||
description: "[
|
||||
Default HTTP_CLIENT based on LIBCURL_HTTP_CLIENT.
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
DEFAULT_HTTP_CLIENT
|
||||
|
||||
inherit
|
||||
LIBCURL_HTTP_CLIENT
|
||||
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
note
|
||||
description: "[
|
||||
Default HTTP_CLIENT based on LIBCURL_HTTP_CLIENT.
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
DEFAULT_HTTP_CLIENT
|
||||
|
||||
inherit
|
||||
HTTP_CLIENT
|
||||
|
||||
feature -- Access
|
||||
|
||||
new_session (a_base_url: READABLE_STRING_8): HTTP_CLIENT_SESSION
|
||||
-- Create a new session using `a_base_url'.
|
||||
local
|
||||
libcurl: LIBCURL_HTTP_CLIENT
|
||||
net: NET_HTTP_CLIENT
|
||||
do
|
||||
--| For now, try libcurl first, and then net
|
||||
--| the reason is the net implementation is still in progress.
|
||||
create libcurl
|
||||
Result := libcurl.new_session (a_base_url)
|
||||
if not Result.is_available then
|
||||
create net
|
||||
Result := net.new_session (a_base_url)
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
note
|
||||
description: "[
|
||||
Default HTTP_CLIENT based on NET_HTTP_CLIENT.
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
DEFAULT_HTTP_CLIENT
|
||||
|
||||
inherit
|
||||
NET_HTTP_CLIENT
|
||||
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
note
|
||||
description: "[
|
||||
Default HTTP_CLIENT based on NULL_HTTP_CLIENT.
|
||||
]"
|
||||
author: "$Author$"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
DEFAULT_HTTP_CLIENT
|
||||
|
||||
inherit
|
||||
NULL_HTTP_CLIENT
|
||||
|
||||
end
|
||||
@@ -9,7 +9,7 @@ note
|
||||
deferred class
|
||||
HTTP_CLIENT
|
||||
|
||||
feature -- Status
|
||||
feature -- Access
|
||||
|
||||
new_session (a_base_url: READABLE_STRING_8): HTTP_CLIENT_SESSION
|
||||
-- Create a new session using `a_base_url'.
|
||||
|
||||
@@ -95,6 +95,24 @@ feature -- Access
|
||||
Result := s
|
||||
end
|
||||
|
||||
multiple_header (a_name: READABLE_STRING_8): detachable LIST [READABLE_STRING_8]
|
||||
-- Header multiple entries related to `a_name'
|
||||
local
|
||||
k: READABLE_STRING_8
|
||||
do
|
||||
across
|
||||
headers as hds
|
||||
loop
|
||||
k := hds.item.name
|
||||
if k.same_string (a_name) then
|
||||
if Result = Void then
|
||||
create {ARRAYED_LIST [READABLE_STRING_8]} Result.make (1)
|
||||
end
|
||||
Result.force (hds.item.value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
headers: LIST [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]
|
||||
-- Computed table of http headers of the response.
|
||||
--| We use a LIST since one might have multiple message-header fields with the same field-name
|
||||
|
||||
@@ -14,18 +14,6 @@ class
|
||||
inherit
|
||||
HTTP_CLIENT
|
||||
|
||||
create
|
||||
default_create,
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
default_create
|
||||
end
|
||||
|
||||
feature -- Status
|
||||
|
||||
new_session (a_base_url: READABLE_STRING_8): NET_HTTP_CLIENT_SESSION
|
||||
@@ -28,6 +28,16 @@ feature {NONE} -- Internal
|
||||
session: NET_HTTP_CLIENT_SESSION
|
||||
net_http_client_version: STRING = "0.1"
|
||||
|
||||
|
||||
new_socket (a_host: READABLE_STRING_8; a_port: INTEGER; a_is_https: BOOLEAN; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): NETWORK_STREAM_SOCKET
|
||||
do
|
||||
if a_is_https then
|
||||
create {SSL_NETWORK_STREAM_SOCKET} Result.make_client_by_port (a_port, a_host)
|
||||
else
|
||||
create Result.make_client_by_port (a_port, a_host)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
response: HTTP_CLIENT_RESPONSE
|
||||
@@ -40,12 +50,13 @@ feature -- Access
|
||||
l_cookie: detachable READABLE_STRING_8
|
||||
l_request_uri: STRING
|
||||
l_url: HTTP_URL
|
||||
socket: NETWORK_STREAM_SOCKET
|
||||
l_socket: NETWORK_STREAM_SOCKET
|
||||
s: STRING
|
||||
l_message: STRING
|
||||
l_content_length: INTEGER
|
||||
l_location: detachable READABLE_STRING_8
|
||||
l_port: INTEGER
|
||||
l_is_https: BOOLEAN
|
||||
l_authorization: HTTP_AUTHORIZATION
|
||||
l_platform: STRING
|
||||
l_upload_data: detachable READABLE_STRING_8
|
||||
@@ -69,13 +80,13 @@ feature -- Access
|
||||
end
|
||||
create Result.make (url)
|
||||
|
||||
create l_form_string.make_empty
|
||||
|
||||
-- Get URL data
|
||||
l_is_https := url.starts_with_general ("https://")
|
||||
create l_uri.make_from_string (url)
|
||||
l_port := l_uri.port
|
||||
if l_port = 0 then
|
||||
if url.starts_with_general ("https://") then
|
||||
if l_is_https then
|
||||
l_port := 443
|
||||
else
|
||||
l_port := 80
|
||||
@@ -88,6 +99,15 @@ feature -- Access
|
||||
l_host := l_url.host
|
||||
end
|
||||
|
||||
-- Connect
|
||||
l_socket := new_socket (l_host, l_port, l_is_https, ctx)
|
||||
l_socket.set_connect_timeout (connect_timeout)
|
||||
l_socket.set_timeout (timeout)
|
||||
l_socket.connect
|
||||
if l_socket.is_connected then
|
||||
|
||||
create l_form_string.make_empty
|
||||
|
||||
-- add headers for authorization
|
||||
if not headers.has ("Authorization") then
|
||||
if
|
||||
@@ -220,12 +240,6 @@ feature -- Access
|
||||
end
|
||||
end
|
||||
|
||||
-- Connect
|
||||
create socket.make_client_by_port (l_port, l_host)
|
||||
socket.set_connect_timeout (connect_timeout)
|
||||
socket.set_timeout (timeout)
|
||||
socket.connect
|
||||
if socket.is_connected then
|
||||
-- FIXME: check usage of headers and specific header variable.
|
||||
--| only one Cookie: is allowed, so merge multiple into one;
|
||||
--| if Host is in header, use that one.
|
||||
@@ -295,20 +309,32 @@ feature -- Access
|
||||
--| Note that any remaining file to upload will be done directly via the socket
|
||||
--| to optimize memory usage
|
||||
|
||||
--| Send request
|
||||
if socket.ready_for_writing then
|
||||
socket.put_string (s)
|
||||
|
||||
--|-----------------------------|--
|
||||
--| Request preparation is done |--
|
||||
--|-----------------------------|--
|
||||
|
||||
if l_socket.ready_for_writing then
|
||||
--| Socket is ready for writing, so let's send the request.
|
||||
|
||||
--|-------------------------|--
|
||||
--| Send request |--
|
||||
--|-------------------------|--
|
||||
|
||||
l_socket.put_string (s)
|
||||
--| Send remaining payload data, if needed.
|
||||
if l_upload_file /= Void then
|
||||
-- i.e: not yet processed
|
||||
append_file_content_to_socket (l_upload_file, l_upload_file.count, socket)
|
||||
append_file_content_to_socket (l_upload_file, l_upload_file.count, l_socket)
|
||||
end
|
||||
|
||||
--| Get response.
|
||||
--| Get header message
|
||||
if socket.ready_for_reading then
|
||||
--|-------------------------|--
|
||||
--| Get response. |--
|
||||
--| Get header message |--
|
||||
--|-------------------------|--
|
||||
if l_socket.ready_for_reading then
|
||||
create l_message.make_empty
|
||||
append_socket_header_content_to (socket, l_message)
|
||||
append_socket_header_content_to (l_socket, l_message)
|
||||
l_prev_header := Result.raw_header
|
||||
Result.set_raw_header (l_message.string)
|
||||
l_content_length := -1
|
||||
@@ -316,13 +342,13 @@ feature -- Access
|
||||
l_content_length := s_len.to_integer
|
||||
end
|
||||
l_location := Result.header ("Location")
|
||||
if attached Result.header ("Set-Cookies") as s_cookies then
|
||||
if attached Result.header ("Set-Cookie") as s_cookies then
|
||||
session.set_cookie (s_cookies)
|
||||
end
|
||||
l_message.append (http_end_of_header_line)
|
||||
|
||||
-- Get content if any.
|
||||
append_socket_content_to (Result, socket, l_content_length, l_message)
|
||||
append_socket_content_to (Result, l_socket, l_content_length, l_message)
|
||||
-- Restore previous header
|
||||
Result.set_raw_header (l_prev_header)
|
||||
-- Set message
|
||||
@@ -455,33 +481,47 @@ feature {NONE} -- Helpers
|
||||
end
|
||||
end
|
||||
|
||||
append_socket_content_to (a_response: HTTP_CLIENT_RESPONSE; a_socket: NETWORK_STREAM_SOCKET; a_len: INTEGER; a_buffer: STRING)
|
||||
-- Get content from `a_socket' and append it to `a_buffer'.
|
||||
append_socket_content_to (a_response: HTTP_CLIENT_RESPONSE; a_socket: NETWORK_STREAM_SOCKET; a_len: INTEGER; a_output: STRING)
|
||||
-- Get content from `a_socket' and append it to `a_output'.
|
||||
-- If `a_len' is negative, try to get as much as possible,
|
||||
-- this is probably HTTP/1.0 without any Content-Length.
|
||||
local
|
||||
s: STRING_8
|
||||
r: INTEGER -- remaining count
|
||||
n,pos, l_chunk_size, l_count: INTEGER
|
||||
hexa2int: HEXADECIMAL_STRING_TO_INTEGER_CONVERTER
|
||||
do
|
||||
if a_socket.readable then
|
||||
if a_len >= 0 then
|
||||
debug ("socket_content")
|
||||
io.error.put_string ("Content-Length="+ a_len.out +"%N")
|
||||
end
|
||||
from
|
||||
n := a_len
|
||||
r := a_len
|
||||
until
|
||||
n = 0 or else not a_socket.readable or else a_response.error_occurred
|
||||
r = 0 or else not a_socket.readable or else a_response.error_occurred
|
||||
loop
|
||||
if a_socket.ready_for_reading then
|
||||
a_socket.read_stream_thread_aware (n)
|
||||
a_socket.read_stream_thread_aware (r)
|
||||
l_count := l_count + a_socket.bytes_read
|
||||
n := n - a_socket.bytes_read
|
||||
a_buffer.append (a_socket.last_string)
|
||||
debug ("socket_content")
|
||||
io.error.put_string (" - byte read=" + a_socket.bytes_read.out + "%N")
|
||||
io.error.put_string (" - current count=" + l_count.out + "%N")
|
||||
end
|
||||
r := r - a_socket.bytes_read
|
||||
a_output.append (a_socket.last_string)
|
||||
else
|
||||
debug ("socket_content")
|
||||
io.error.put_string (" -! TIMEOUT%N")
|
||||
end
|
||||
a_response.set_error_message ("Could not read chunked data, timeout")
|
||||
end
|
||||
end
|
||||
check full_content_read: l_count = a_len end
|
||||
check full_content_read: not a_response.error_occurred implies l_count = a_len end
|
||||
elseif attached a_response.header ("Transfer-Encoding") as l_enc and then l_enc.is_case_insensitive_equal ("chunked") then
|
||||
debug ("socket_content")
|
||||
io.error.put_string ("Chunked encoding%N")
|
||||
end
|
||||
from
|
||||
create hexa2int.make
|
||||
n := 1
|
||||
@@ -491,6 +531,9 @@ feature {NONE} -- Helpers
|
||||
a_socket.read_line_thread_aware -- Read chunk info
|
||||
s := a_socket.last_string
|
||||
s.right_adjust
|
||||
debug ("socket_content")
|
||||
io.error.put_string (" - chunk info='" + s + "'%N")
|
||||
end
|
||||
pos := s.index_of (';', 1)
|
||||
if pos > 0 then
|
||||
s.keep_head (pos - 1)
|
||||
@@ -505,17 +548,28 @@ feature {NONE} -- Helpers
|
||||
n := 0
|
||||
end
|
||||
end
|
||||
debug ("socket_content")
|
||||
io.error.put_string (" - chunk size=" + n.out + "%N")
|
||||
end
|
||||
if n > 0 then
|
||||
from
|
||||
r := n
|
||||
until
|
||||
n = 0 or else not a_socket.readable or else a_response.error_occurred
|
||||
r = 0 or else not a_socket.readable or else a_response.error_occurred
|
||||
loop
|
||||
if a_socket.ready_for_reading then
|
||||
a_socket.read_stream_thread_aware (n)
|
||||
a_socket.read_stream_thread_aware (r)
|
||||
l_count := l_count + a_socket.bytes_read
|
||||
n := n - a_socket.bytes_read
|
||||
a_buffer.append (a_socket.last_string)
|
||||
debug ("socket_content")
|
||||
io.error.put_string (" - byte read=" + a_socket.bytes_read.out + "%N")
|
||||
io.error.put_string (" - current count=" + l_count.out + "%N")
|
||||
end
|
||||
r := r - a_socket.bytes_read
|
||||
a_output.append (a_socket.last_string)
|
||||
else
|
||||
debug ("socket_content")
|
||||
io.error.put_string (" -! TIMEOUT%N")
|
||||
end
|
||||
a_response.set_error_message ("Could not read chunked data, timeout")
|
||||
end
|
||||
end
|
||||
@@ -525,7 +579,13 @@ feature {NONE} -- Helpers
|
||||
check a_socket.last_character = '%R' end
|
||||
a_socket.read_character
|
||||
check a_socket.last_character = '%N' end
|
||||
debug ("socket_content")
|
||||
io.error.put_string (" - Found CRNL %N")
|
||||
end
|
||||
else
|
||||
debug ("socket_content")
|
||||
io.error.put_string (" -! TIMEOUT%N")
|
||||
end
|
||||
a_response.set_error_message ("Could not read chunked data, timeout")
|
||||
end
|
||||
end
|
||||
@@ -546,7 +606,7 @@ feature {NONE} -- Helpers
|
||||
s := a_socket.last_string
|
||||
n := a_socket.bytes_read
|
||||
l_count := l_count + n
|
||||
a_buffer.append (s)
|
||||
a_output.append (s)
|
||||
else
|
||||
a_response.set_error_message ("Could not read data, timeout")
|
||||
end
|
||||
@@ -11,6 +11,8 @@ class
|
||||
inherit
|
||||
HTTP_CLIENT_SESSION
|
||||
|
||||
NET_HTTP_CLIENT_INFO
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
@@ -22,8 +24,14 @@ feature {NONE} -- Initialization
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_available: BOOLEAN = True
|
||||
is_available: BOOLEAN
|
||||
-- Is interface usable?
|
||||
do
|
||||
Result := True
|
||||
if base_url.starts_with_general ("https://") then
|
||||
Result := has_https_support
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Custom
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
note
|
||||
description: "Additional information related to NET HTTP Client.."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
NET_HTTP_CLIENT_INFO
|
||||
|
||||
feature -- Access
|
||||
|
||||
has_https_support: BOOLEAN = False
|
||||
-- Is HTTPS supported?
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
note
|
||||
description: "[
|
||||
A fake SSL network stream socket... when SSL is disabled at compilation time.
|
||||
Its behavior is similar to NETWORK_STREAM_SOCKET.
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
SSL_NETWORK_STREAM_SOCKET
|
||||
|
||||
inherit
|
||||
NETWORK_STREAM_SOCKET
|
||||
|
||||
create
|
||||
make, make_empty, make_client_by_port, make_client_by_address_and_port, make_server_by_port, make_loopback_server_by_port
|
||||
|
||||
create {SSL_NETWORK_STREAM_SOCKET}
|
||||
make_from_descriptor_and_address, create_from_descriptor
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
note
|
||||
description: "Additional information related to NET HTTP Client.."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
NET_HTTP_CLIENT_INFO
|
||||
|
||||
feature -- Access
|
||||
|
||||
has_https_support: BOOLEAN = True
|
||||
-- Is HTTPS supported?
|
||||
|
||||
note
|
||||
copyright: "2011-2015, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -10,6 +10,8 @@
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<variable name="netssl_http_client_enabled" value="false"/>
|
||||
<variable name="libcurl_http_client_disabled" value="false"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="http_client" location="..\http_client-safe.ecf" readonly="false" use_application_options="true">
|
||||
<option>
|
||||
@@ -17,6 +19,19 @@
|
||||
</option>
|
||||
</library>
|
||||
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
||||
<tests name="tests" location=".\"/>
|
||||
<tests name="tests" location=".\">
|
||||
<file_rule>
|
||||
<exclude>.*libcurl_.*.e$</exclude>
|
||||
<condition>
|
||||
<custom name="libcurl_http_client_disabled" value="true"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
<file_rule>
|
||||
<exclude>.*net_.*.e$</exclude>
|
||||
<condition>
|
||||
<custom name="net_http_client_disabled" value="true"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
</tests>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -13,16 +13,40 @@ feature -- Init
|
||||
if attached null.new_session ("http://example.com/") as l_sess then
|
||||
check not l_sess.is_available end
|
||||
end
|
||||
test_get_with_authentication
|
||||
test_http_client
|
||||
end
|
||||
|
||||
test_get_with_authentication
|
||||
local
|
||||
cl: DEFAULT_HTTP_CLIENT
|
||||
sess: HTTP_CLIENT_SESSION
|
||||
ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||
do
|
||||
-- GET REQUEST WITH AUTHENTICATION, see http://browserspy.dk/password.php
|
||||
-- check header WWW-Authenticate is received (authentication successful)
|
||||
create cl
|
||||
sess := cl.new_session ("http://browserspy.dk")
|
||||
sess.set_credentials ("test", "test")
|
||||
create ctx.make_with_credentials_required
|
||||
if attached sess.get ("/password-ok.php", ctx) as res 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>"))
|
||||
else
|
||||
assert ("has body", False)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test_http_client
|
||||
-- New test routine
|
||||
local
|
||||
sess: LIBCURL_HTTP_CLIENT_SESSION
|
||||
cl: DEFAULT_HTTP_CLIENT
|
||||
sess: HTTP_CLIENT_SESSION
|
||||
h: STRING_8
|
||||
do
|
||||
create sess.make ("http://www.google.com")
|
||||
create cl
|
||||
sess := cl.new_session ("http://www.google.com")
|
||||
if attached sess.get ("/search?q=eiffel", Void) as res then
|
||||
assert ("Get returned without error", not res.error_occurred)
|
||||
create h.make_empty
|
||||
|
||||
@@ -47,21 +47,30 @@ feature -- Test routines
|
||||
end
|
||||
end
|
||||
|
||||
test_http_client_requestbin
|
||||
test_http_client_ssl
|
||||
-- New test routine
|
||||
local
|
||||
sess: like new_session
|
||||
h: STRING_8
|
||||
do
|
||||
sess := new_session ("http://requestb.in")
|
||||
sess := new_session ("https://www.eiffel.org")
|
||||
if attached sess.get ("/welcome", Void) as res then
|
||||
assert ("Get returned without error", not res.error_occurred)
|
||||
create h.make_empty
|
||||
if attached sess.get ("/1a0q2h61", Void).headers as hds then
|
||||
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 l_body then
|
||||
assert ("body not empty", not l_body.is_empty)
|
||||
else
|
||||
assert ("missing body", False)
|
||||
end
|
||||
assert ("same headers", h.same_string (res.raw_header))
|
||||
end
|
||||
end
|
||||
|
||||
test_headers
|
||||
|
||||
@@ -27,9 +27,9 @@ feature -- Tests
|
||||
test_http_client
|
||||
end
|
||||
|
||||
test_libcurl_http_client_requestbin
|
||||
test_libcurl_http_client_ssl
|
||||
do
|
||||
test_http_client_requestbin
|
||||
test_http_client_ssl
|
||||
end
|
||||
|
||||
test_libcurl_headers
|
||||
|
||||
@@ -27,9 +27,9 @@ feature -- Tests
|
||||
test_http_client
|
||||
end
|
||||
|
||||
test_net_http_client_requestbin
|
||||
test_net_http_client_ssl
|
||||
do
|
||||
test_http_client_requestbin
|
||||
test_http_client_ssl
|
||||
end
|
||||
|
||||
test_net_headers
|
||||
|
||||
Reference in New Issue
Block a user