diff --git a/library/client/http_client/http_client-safe.ecf b/library/client/http_client/http_client-safe.ecf
new file mode 100644
index 00000000..e3a15665
--- /dev/null
+++ b/library/client/http_client/http_client-safe.ecf
@@ -0,0 +1,36 @@
+
+
+
+
+
+ /.git$
+ /EIFGENs$
+ /.svn$
+
+
+
+
+
+
+
+ /request$
+
+
+
+
+
+
+
+ /.git$
+ /EIFGENs$
+ /.svn$
+
+
+
+
+
+
+
diff --git a/library/client/http_client/http_client.ecf b/library/client/http_client/http_client.ecf
new file mode 100644
index 00000000..0240a509
--- /dev/null
+++ b/library/client/http_client/http_client.ecf
@@ -0,0 +1,21 @@
+
+
+
+
+
+ /.git$
+ /EIFGENs$
+ /.svn$
+
+
+
+
+
+
+
+ /request$
+
+
+
+
diff --git a/library/client/http_client/src/http_client.e b/library/client/http_client/src/http_client.e
new file mode 100644
index 00000000..f415811f
--- /dev/null
+++ b/library/client/http_client/src/http_client.e
@@ -0,0 +1,16 @@
+note
+ description : "Objects that ..."
+ author : "$Author$"
+ date : "$Date$"
+ revision : "$Revision$"
+
+deferred class
+ HTTP_CLIENT
+
+feature -- Status
+
+ new_session (a_base_url: READABLE_STRING_8): HTTP_CLIENT_SESSION
+ deferred
+ end
+
+end
diff --git a/library/client/http_client/src/http_client_constants.e b/library/client/http_client/src/http_client_constants.e
new file mode 100644
index 00000000..7586451c
--- /dev/null
+++ b/library/client/http_client/src/http_client_constants.e
@@ -0,0 +1,37 @@
+note
+ description: "Summary description for {HTTP_CLIENT_CONSTANTS}."
+ author: ""
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ HTTP_CLIENT_CONSTANTS
+
+feature -- Auth type
+
+ auth_type_id (a_auth_type_string: READABLE_STRING_8): INTEGER
+ local
+ s: STRING_8
+ do
+ create s.make_from_string (a_auth_type_string)
+ s.to_lower
+ if s.same_string_general ("basic") then
+ Result := Auth_type_basic
+ elseif s.same_string_general ("digest") then
+ Result := Auth_type_digest
+ elseif s.same_string_general ("any") then
+ Result := Auth_type_any
+ elseif s.same_string_general ("anysafe") then
+ Result := Auth_type_anysafe
+ elseif s.same_string_general ("none") then
+ Result := Auth_type_none
+ end
+ end
+
+ Auth_type_none: INTEGER = 0
+ Auth_type_basic: INTEGER = 1
+ Auth_type_digest: INTEGER = 2
+ Auth_type_any: INTEGER = 3
+ Auth_type_anysafe: INTEGER = 4
+
+end
diff --git a/library/client/http_client/src/http_client_request.e b/library/client/http_client/src/http_client_request.e
new file mode 100644
index 00000000..edb36b5d
--- /dev/null
+++ b/library/client/http_client/src/http_client_request.e
@@ -0,0 +1,183 @@
+note
+ description : "Objects that ..."
+ author : "$Author$"
+ date : "$Date$"
+ revision : "$Revision$"
+
+deferred class
+ HTTP_CLIENT_REQUEST
+
+inherit
+ REFACTORING_HELPER
+
+feature {NONE} -- Initialization
+
+ make (a_url: READABLE_STRING_8; a_session: like session)
+ -- Initialize `Current'.
+ do
+ session := a_session
+ url := a_url
+ headers := session.headers.twin
+ end
+
+ session: HTTP_CLIENT_SESSION
+
+feature -- Access
+
+ request_method: READABLE_STRING_8
+ deferred
+ end
+
+ url: READABLE_STRING_8
+
+ headers: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
+
+feature -- Execution
+
+ import (ctx: HTTP_CLIENT_REQUEST_CONTEXT)
+ do
+ headers.fill (ctx.headers)
+ end
+
+ execute (ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ deferred
+ end
+
+feature -- Authentication
+
+ auth_type: STRING
+ -- Set the authentication type for the request.
+ -- Types: "basic", "digest", "any"
+ do
+ Result := session.auth_type
+ end
+
+ auth_type_id: INTEGER
+ -- Set the authentication type for the request.
+ -- Types: "basic", "digest", "any"
+ do
+ Result := session.auth_type_id
+ end
+
+ username: detachable READABLE_STRING_8
+ do
+ Result := session.username
+ end
+
+ password: detachable READABLE_STRING_8
+ do
+ Result := session.password
+ end
+
+ credentials: detachable READABLE_STRING_8
+ do
+ Result := session.credentials
+ end
+
+feature -- Settings
+
+ timeout: INTEGER
+ -- HTTP transaction timeout in seconds.
+ do
+ Result := session.timeout
+ end
+
+ connect_timeout: INTEGER
+ -- HTTP connection timeout in seconds.
+ do
+ Result := session.connect_timeout
+ end
+
+ max_redirects: INTEGER
+ -- Maximum number of times to follow redirects.
+ do
+ Result := session.max_redirects
+ end
+
+ ignore_content_length: BOOLEAN
+ -- Does this session ignore Content-Size headers?
+ do
+ Result := session.ignore_content_length
+ end
+
+ buffer_size: NATURAL
+ -- Set the buffer size for request. This option will
+ -- only be set if buffer_size is positive
+ do
+ Result := session.buffer_size
+ end
+
+ default_response_charset: detachable READABLE_STRING_8
+ -- Default encoding of responses. Used if no charset is provided by the host.
+ do
+ Result := session.default_response_charset
+ end
+
+feature {NONE} -- Utilities
+
+ append_parameters_to_url (a_url: STRING; a_parameters: detachable ARRAY [detachable TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
+ -- Append parameters `a_parameters' to `a_url'
+ require
+ a_url_attached: a_url /= Void
+ local
+ i: INTEGER
+ l_first_param: BOOLEAN
+ do
+ if a_parameters /= Void and then 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
+ i := a_parameters.lower
+ until
+ i > a_parameters.upper
+ loop
+ if attached a_parameters[i] as a_param then
+ if l_first_param then
+ a_url.append_character ('?')
+ else
+ a_url.append_character ('&')
+ end
+ a_url.append_string (a_param.name)
+ a_url.append_character ('=')
+ a_url.append_string (a_param.value)
+ l_first_param := False
+ end
+ i := i + 1
+ 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
+
+end
diff --git a/library/client/http_client/src/http_client_request_context.e b/library/client/http_client/src/http_client_request_context.e
new file mode 100644
index 00000000..8ffd0e9d
--- /dev/null
+++ b/library/client/http_client/src/http_client_request_context.e
@@ -0,0 +1,48 @@
+note
+ description: "Summary description for {HTTP_CLIENT_REQUEST_CONTEXT}."
+ author: ""
+ date: "$Date$"
+ revision: "$Revision$"
+
+class
+ HTTP_CLIENT_REQUEST_CONTEXT
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ do
+ create headers.make (2)
+ create query_parameters.make (5)
+ create form_data_parameters.make (10)
+ end
+
+feature -- Settings
+
+ credentials_required: BOOLEAN
+
+feature -- Access
+
+ headers: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
+
+ query_parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_8]
+
+ form_data_parameters: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_8]
+
+feature -- Status report
+
+ has_form_data: BOOLEAN
+ do
+ Result := not form_data_parameters.is_empty
+ end
+
+feature -- Element change
+
+ set_credentials_required (b: BOOLEAN)
+ do
+ credentials_required := b
+ end
+
+end
diff --git a/library/client/http_client/src/http_client_response.e b/library/client/http_client/src/http_client_response.e
new file mode 100644
index 00000000..c7f46d28
--- /dev/null
+++ b/library/client/http_client/src/http_client_response.e
@@ -0,0 +1,60 @@
+note
+ description : "Objects that ..."
+ author : "$Author$"
+ date : "$Date$"
+ revision : "$Revision$"
+
+class
+ HTTP_CLIENT_RESPONSE
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ -- Initialize `Current'.
+ do
+ status := 200
+ raw_headers := ""
+ end
+
+feature -- Status
+
+feature -- Access
+
+ status: INTEGER assign set_status
+
+ raw_headers: READABLE_STRING_8
+
+ headers: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
+ local
+ tb: like internal_headers
+ do
+ tb := internal_headers
+ if tb = Void then
+ create tb.make (3)
+ internal_headers := tb
+ end
+ Result := tb
+ end
+
+ body: detachable READABLE_STRING_8 assign set_body
+
+feature -- Change
+
+ set_status (s: INTEGER)
+ do
+ status := s
+ end
+
+ set_body (s: like body)
+ do
+ body := s
+ end
+
+feature {NONE} -- Implementation
+
+ internal_headers: detachable like headers
+
+end
diff --git a/library/client/http_client/src/http_client_session.e b/library/client/http_client/src/http_client_session.e
new file mode 100644
index 00000000..964958f5
--- /dev/null
+++ b/library/client/http_client/src/http_client_session.e
@@ -0,0 +1,163 @@
+note
+ description : "Objects that ..."
+ author : "$Author$"
+ date : "$Date$"
+ revision : "$Revision$"
+
+deferred class
+ HTTP_CLIENT_SESSION
+
+feature {NONE} -- Initialization
+
+ make (a_base_url: READABLE_STRING_8)
+ -- Initialize `Current'.
+ do
+ set_defaults
+ create headers.make (3)
+
+ base_url := a_base_url
+ initialize
+ end
+
+ set_defaults
+ do
+ timeout := 5
+ connect_timeout := 1
+ max_redirects := 5
+ set_basic_auth_type
+ end
+
+ initialize
+ deferred
+ end
+
+feature -- Basic operation
+
+ get (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ deferred
+ end
+
+ head (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ deferred
+ end
+
+ post (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ deferred
+ end
+
+ put (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ deferred
+ end
+
+ delete (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ deferred
+ end
+
+feature -- Settings
+
+ timeout: INTEGER
+ -- HTTP transaction timeout in seconds. Defaults to 5 seconds.
+
+
+ connect_timeout: INTEGER
+ -- HTTP connection timeout in seconds. Defaults to 1 second.
+
+ max_redirects: INTEGER
+ -- Maximum number of times to follow redirects.
+ -- Set to 0 to disable and -1 to follow all redirects. Defaults to 5.
+
+ ignore_content_length: BOOLEAN
+ -- Does this session ignore Content-Size headers?
+
+ buffer_size: NATURAL
+ -- Set the buffer size for request. This option will
+ -- only be set if buffer_size is positive
+
+ default_response_charset: detachable READABLE_STRING_8
+ -- Default encoding of responses. Used if no charset is provided by the host.
+
+feature -- Access
+
+ base_url: READABLE_STRING_8
+
+ headers: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
+
+feature -- Authentication
+
+ auth_type: STRING
+ -- Set the authentication type for the request.
+ -- Types: "basic", "digest", "any"
+
+ auth_type_id: INTEGER
+ -- See {HTTP_CLIENT_CONSTANTS}.Auth_type_*
+
+ username,
+ password: detachable READABLE_STRING_8
+
+ credentials: detachable READABLE_STRING_8
+
+feature -- Change
+
+ set_timeout (n: like timeout)
+ do
+ timeout := n
+ end
+
+ set_user_agent (v: READABLE_STRING_8)
+ do
+ add_header ("User-Agent", v)
+ end
+
+ add_header (k: READABLE_STRING_8; v: READABLE_STRING_8)
+ do
+ headers.force (v, k)
+ end
+
+ set_credentials (u: like username; p: like password)
+ do
+ username := u
+ password := p
+ if u /= Void and p /= Void then
+ credentials := u + ":" + p
+ else
+ credentials := Void
+ end
+ end
+
+ set_auth_type (s: READABLE_STRING_8)
+ do
+ auth_type := s
+ auth_type_id := http_client_constants.auth_type_id (s)
+ end
+
+ set_basic_auth_type
+ do
+ auth_type := "basic"
+ auth_type_id := {HTTP_CLIENT_CONSTANTS}.auth_type_basic
+ end
+
+ set_digest_auth_type
+ do
+ auth_type := "digest"
+ auth_type_id := {HTTP_CLIENT_CONSTANTS}.auth_type_digest
+ end
+
+ set_any_auth_type
+ do
+ auth_type := "any"
+ auth_type_id := {HTTP_CLIENT_CONSTANTS}.auth_type_any
+ end
+
+ set_anysafe_auth_type
+ do
+ auth_type := "anysafe"
+ auth_type_id := {HTTP_CLIENT_CONSTANTS}.auth_type_anysafe
+ end
+
+feature {NONE} -- Implementation
+
+ http_client_constants: HTTP_CLIENT_CONSTANTS
+ once
+ create Result
+ end
+end
diff --git a/library/client/http_client/src/spec/libcurl/libcurl_http_client.e b/library/client/http_client/src/spec/libcurl/libcurl_http_client.e
new file mode 100644
index 00000000..560fdf40
--- /dev/null
+++ b/library/client/http_client/src/spec/libcurl/libcurl_http_client.e
@@ -0,0 +1,30 @@
+note
+ description : "Objects that ..."
+ author : "$Author$"
+ date : "$Date$"
+ revision : "$Revision$"
+
+class
+ LIBCURL_HTTP_CLIENT
+
+inherit
+ HTTP_CLIENT
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ -- Initialize `Current'.
+ do
+ end
+
+feature -- Status
+
+ new_session (a_base_url: READABLE_STRING_8): LIBCURL_HTTP_CLIENT_SESSION
+ do
+ create Result.make (a_base_url)
+ end
+
+end
diff --git a/library/client/http_client/src/spec/libcurl/libcurl_http_client_request.e b/library/client/http_client/src/spec/libcurl/libcurl_http_client_request.e
new file mode 100644
index 00000000..a6ec2f1a
--- /dev/null
+++ b/library/client/http_client/src/spec/libcurl/libcurl_http_client_request.e
@@ -0,0 +1,192 @@
+note
+ description : "Objects that ..."
+ author : "$Author$"
+ date : "$Date$"
+ revision : "$Revision$"
+
+class
+ LIBCURL_HTTP_CLIENT_REQUEST
+
+inherit
+ HTTP_CLIENT_REQUEST
+ rename
+ make as make_request
+ redefine
+ session
+ end
+
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_url: READABLE_STRING_8; a_request_method: like request_method; a_session: like session)
+ do
+ make_request (a_url, a_session)
+ request_method := a_request_method
+ end
+
+ session: LIBCURL_HTTP_CLIENT_SESSION
+
+feature -- Access
+
+ request_method: READABLE_STRING_8
+
+feature -- Execution
+
+ execute (ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ local
+ l_result: INTEGER
+ l_curl_string: CURL_STRING
+ l_url: READABLE_STRING_8
+ p: POINTER
+ a_data: CELL [detachable ANY]
+ l_form, l_last: CURL_FORM
+ curl: CURL_EXTERNALS
+ curl_easy: CURL_EASY_EXTERNALS
+ curl_handle: POINTER
+ do
+ curl := session.curl
+ curl_easy := session.curl_easy
+
+ l_url := url
+ if ctx /= Void then
+ if attached ctx.query_parameters as l_query_params then
+ from
+ l_query_params.start
+ until
+ l_query_params.after
+ loop
+ append_parameters_to_url (l_url, <<[l_query_params.key_for_iteration, urlencode (l_query_params.item_for_iteration)]>>)
+ l_query_params.forth
+ end
+ end
+ end
+
+ --| Configure cURL session
+ curl_handle := curl_easy.init
+
+ --| URL
+ curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_url, l_url)
+
+ --| Timeout
+ if timeout > 0 then
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_timeout, timeout)
+ end
+ --| Connect Timeout
+ if connect_timeout > 0 then
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_connecttimeout, timeout)
+ end
+ --| Redirection
+ if max_redirects /= 0 then
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_followlocation, 1)
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_maxredirs, max_redirects)
+ else
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_followlocation, 0)
+ end
+
+ if request_method.is_case_insensitive_equal ("GET") then
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpget, 1)
+ elseif request_method.is_case_insensitive_equal ("POST") then
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_post, 1)
+ elseif request_method.is_case_insensitive_equal ("PUT") then
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_put, 1)
+ elseif request_method.is_case_insensitive_equal ("HEAD") then
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_nobody, 1)
+ elseif request_method.is_case_insensitive_equal ("DELETE") then
+ curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_customrequest, "DELETE")
+ else
+ curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_customrequest, request_method)
+ --| ignored
+ end
+
+ --| Credential
+ if ctx /= Void and then ctx.credentials_required then
+ if attached credentials as l_credentials then
+ inspect auth_type_id
+ when {HTTP_CLIENT_CONSTANTS}.Auth_type_none then
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpauth, {CURL_OPT_CONSTANTS}.curlauth_none)
+ when {HTTP_CLIENT_CONSTANTS}.Auth_type_basic then
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpauth, {CURL_OPT_CONSTANTS}.curlauth_basic)
+ when {HTTP_CLIENT_CONSTANTS}.Auth_type_digest then
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpauth, {CURL_OPT_CONSTANTS}.curlauth_digest)
+ when {HTTP_CLIENT_CONSTANTS}.Auth_type_any then
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpauth, {CURL_OPT_CONSTANTS}.curlauth_any)
+ when {HTTP_CLIENT_CONSTANTS}.Auth_type_anysafe then
+ curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpauth, {CURL_OPT_CONSTANTS}.curlauth_anysafe)
+ else
+ end
+
+ curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_userpwd, l_credentials)
+ else
+ --| Credentials not prov ided ...
+ end
+ end
+
+ if ctx /= Void and then ctx.has_form_data then
+ if attached ctx.form_data_parameters as l_posts and then not l_posts.is_empty then
+-- curl_easy.set_debug_function (curl_handle)
+-- curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_verbose, 1)
+
+ create l_form.make
+ create l_last.make
+ from
+ l_posts.start
+ until
+ l_posts.after
+ loop
+ curl.formadd_string_string (l_form, l_last, {CURL_FORM_CONSTANTS}.CURLFORM_COPYNAME, l_posts.key_for_iteration, {CURL_FORM_CONSTANTS}.CURLFORM_COPYCONTENTS, l_posts.item_for_iteration, {CURL_FORM_CONSTANTS}.CURLFORM_END)
+ l_posts.forth
+ end
+ l_last.release_item
+ curl_easy.setopt_form (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httppost, l_form)
+ end
+ end
+
+
+ curl.global_init
+ if attached headers as l_headers then
+ across
+ l_headers as curs
+ loop
+ p := curl.slist_append (p, curs.key + ": " + curs.item)
+-- curl_easy.setopt_slist (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpheader, p)
+ end
+ end
+
+ p := curl.slist_append (p, "Expect:")
+ curl_easy.setopt_slist (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpheader, p)
+
+
+ curl.global_cleanup
+
+ curl_easy.set_read_function (curl_handle)
+ curl_easy.set_write_function (curl_handle)
+ create l_curl_string.make_empty
+ curl_easy.setopt_curl_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_writedata, l_curl_string)
+
+ debug ("service")
+ io.put_string ("SERVICE: " + l_url)
+ io.put_new_line
+ end
+
+ create Result.make
+ l_result := curl_easy.perform (curl_handle)
+
+ create a_data.put (Void)
+ l_result := curl_easy.getinfo (curl_handle, {CURL_INFO_CONSTANTS}.curlinfo_response_code, a_data)
+ if l_result = 0 and then attached {INTEGER} a_data.item as l_http_status then
+ Result.status := l_http_status
+ else
+ Result.status := 0
+ end
+
+-- last_api_call := l_url
+ curl_easy.cleanup (curl_handle)
+
+
+ Result.body := l_curl_string.string
+ end
+
+end
diff --git a/library/client/http_client/src/spec/libcurl/libcurl_http_client_session.e b/library/client/http_client/src/spec/libcurl/libcurl_http_client_session.e
new file mode 100644
index 00000000..740f4e4e
--- /dev/null
+++ b/library/client/http_client/src/spec/libcurl/libcurl_http_client_session.e
@@ -0,0 +1,85 @@
+note
+ description : "Objects that ..."
+ author : "$Author$"
+ date : "$Date$"
+ revision : "$Revision$"
+
+class
+ LIBCURL_HTTP_CLIENT_SESSION
+
+inherit
+ HTTP_CLIENT_SESSION
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ initialize
+ do
+ create curl -- cURL externals
+ create curl_easy -- cURL easy externals
+ end
+
+feature -- Basic operation
+
+ get (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ local
+ req: HTTP_CLIENT_REQUEST
+ do
+ create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "GET", Current)
+ Result := execute_request (req, ctx)
+ end
+
+ head (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ local
+ req: HTTP_CLIENT_REQUEST
+ do
+ create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "HEAD", Current)
+ Result := execute_request (req, ctx)
+ end
+
+ post (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ local
+ req: HTTP_CLIENT_REQUEST
+ do
+ create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "POST", Current)
+ Result := execute_request (req, ctx)
+ end
+
+ put (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ local
+ req: HTTP_CLIENT_REQUEST
+ do
+ create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "PUT", Current)
+ Result := execute_request (req, ctx)
+ end
+
+ delete (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ local
+ req: HTTP_CLIENT_REQUEST
+ do
+ create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "DELETE", Current)
+ Result := execute_request (req, ctx)
+ end
+
+feature {NONE} -- Implementation
+
+ execute_request (req: HTTP_CLIENT_REQUEST; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
+ do
+ if ctx /= Void then
+ req.import (ctx)
+ end
+ Result := req.execute (ctx)
+ end
+
+feature {LIBCURL_HTTP_CLIENT_REQUEST} -- Curl implementation
+
+ curl: CURL_EXTERNALS
+ -- cURL externals
+
+ curl_easy: CURL_EASY_EXTERNALS
+ -- cURL easy externals
+
+
+end
diff --git a/library/error/src/error_handler.e b/library/error/src/error_handler.e
index 9234990a..c6e72c8b 100644
--- a/library/error/src/error_handler.e
+++ b/library/error/src/error_handler.e
@@ -22,6 +22,7 @@ feature {NONE} -- Initialization
-- Initialize `Current'.
do
create {ARRAYED_LIST [ERROR]} errors.make (3)
+ create error_added_actions
end
feature -- Status
@@ -37,6 +38,8 @@ feature -- Status
Result := errors.count
end
+feature {ERROR_HANDLER, ERROR_VISITOR} -- Restricted access
+
errors: LIST [ERROR]
-- Errors container
@@ -52,12 +55,26 @@ feature -- Status report
end
end
+feature -- Events
+
+ error_added_actions: ACTION_SEQUENCE [TUPLE [ERROR]]
+ -- Actions triggered when a new error is added
+
+feature {NONE} -- Event: implementation
+
+ on_error_added (e: ERROR)
+ -- Error `e' was just added
+ do
+ error_added_actions.call ([e])
+ end
+
feature -- Basic operation
add_error (a_error: ERROR)
-- Add `a_error' to the stack of error
do
errors.force (a_error)
+ on_error_added (a_error)
end
add_error_details, add_custom_error (a_code: INTEGER; a_name: STRING; a_message: detachable STRING_32)
@@ -69,10 +86,25 @@ feature -- Basic operation
add_error (e)
end
- append (a_err_handler: ERROR_HANDLER)
+ append (other: ERROR_HANDLER)
-- Append errors from `a_err_handler'
+ local
+ other_errs: LIST [ERROR]
do
- errors.append (a_err_handler.errors)
+ other_errs := other.errors
+ if other_errs.count > 0 then
+ from
+ other_errs.start
+ until
+ other_errs.after
+ loop
+ add_error (other_errs.item)
+ other_errs.forth
+ end
+ end
+ ensure
+ other_error_appended: other.has_error implies has_error
+ new_count: count = old count + other.count
end
feature -- Access
@@ -107,7 +139,7 @@ feature -- Element changes
do
if count > 1 and then attached as_single_error as e then
wipe_out
- add_error (e)
+ errors.force (e)
end
end
diff --git a/library/error/src/error_handler_with_event.e b/library/error/src/error_handler_with_event.e
new file mode 100644
index 00000000..ac69f3ef
--- /dev/null
+++ b/library/error/src/error_handler_with_event.e
@@ -0,0 +1,11 @@
+note
+
description: "Summary description for {ERROR_HANDLER_WITH_EVENT}."
+
author: ""
+
date: "$Date$"
+
revision: "$Revision$"
+
+
class
+
ERROR_HANDLER_WITH_EVENT
+
+
end
+
\ No newline at end of file
diff --git a/library/server/authentication/http_authorization/http_authorization-safe.ecf b/library/server/authentication/http_authorization/http_authorization-safe.ecf
new file mode 100644
index 00000000..247bb953
--- /dev/null
+++ b/library/server/authentication/http_authorization/http_authorization-safe.ecf
@@ -0,0 +1,16 @@
+
+
+
+
+
+ /.git$
+ /EIFGENs$
+ /.svn$
+
+
+
+
+
+
+
diff --git a/library/server/authentication/http_authorization/http_authorization.ecf b/library/server/authentication/http_authorization/http_authorization.ecf
new file mode 100644
index 00000000..20aa415a
--- /dev/null
+++ b/library/server/authentication/http_authorization/http_authorization.ecf
@@ -0,0 +1,16 @@
+
+
+
+
+
+ /.git$
+ /EIFGENs$
+ /.svn$
+
+
+
+
+
+
+
diff --git a/library/server/authentication/http_authorization/src/http_authorization.e b/library/server/authentication/http_authorization/src/http_authorization.e
new file mode 100644
index 00000000..f35ea83b
--- /dev/null
+++ b/library/server/authentication/http_authorization/src/http_authorization.e
@@ -0,0 +1,48 @@
+note
+ description : "Objects that ..."
+ author : "$Author$"
+ date : "$Date$"
+ revision : "$Revision$"
+
+class
+ HTTP_AUTHORIZATION
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_http_authorization: detachable READABLE_STRING_GENERAL)
+ -- Initialize `Current'.
+ local
+ p: INTEGER
+ s: STRING_8
+ do
+ if attached a_http_authorization as l_auth then
+ s := l_auth.as_string_8
+ if not s.is_empty then
+ p := 1
+ if s[p] = ' ' then
+ p := p + 1
+ end
+ p := s.index_of (' ', p)
+ if p > 0 then
+ s := (create {BASE64}).decoded_string (s.substring (p + 1, s.count))
+ p := s.index_of (':', 1) --| Let's assume ':' is forbidden in login ...
+ if p > 0 then
+ login := s.substring (1, p - 1).as_string_32
+ password := s.substring (p + 1, s.count).as_string_32
+ end
+ end
+ end
+ end
+ end
+
+feature -- Access
+
+ login: detachable READABLE_STRING_32
+
+ password: detachable READABLE_STRING_32
+
+
+end
diff --git a/library/server/ewsgi/specification/request/wgi_request.e b/library/server/ewsgi/specification/request/wgi_request.e
index 75b4d431..2250427c 100644
--- a/library/server/ewsgi/specification/request/wgi_request.e
+++ b/library/server/ewsgi/specification/request/wgi_request.e
@@ -96,6 +96,16 @@ feature -- Access: CGI meta variables
deferred
end
+ meta_string_variable (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
+ -- Environment variable related to `a_name'
+ require
+ a_name_valid: a_name /= Void and then not a_name.is_empty
+ do
+ if attached meta_variable (a_name) as val then
+ Result := val.as_string
+ end
+ end
+
meta_variables: ITERATION_CURSOR [WGI_VALUE]
-- These variables are specific to requests made with HTTP.
-- Interpretation of these variables may depend on the value of
@@ -687,10 +697,10 @@ invariant
query_string_attached: query_string /= Void
remote_addr_attached: remote_addr /= Void
- same_orig_path_info: orig_path_info ~ meta_variable ({WGI_META_NAMES}.orig_path_info)
- same_path_info: path_info ~ meta_variable ({WGI_META_NAMES}.path_info)
+ same_orig_path_info: orig_path_info ~ meta_string_variable ({WGI_META_NAMES}.orig_path_info)
+ same_path_info: path_info ~ meta_string_variable ({WGI_META_NAMES}.path_info)
- path_info_identical: path_info ~ meta_variable ({WGI_META_NAMES}.path_info)
+ path_info_identical: path_info ~ meta_string_variable ({WGI_META_NAMES}.path_info)
note
copyright: "2011-2011, Eiffel Software and others"
diff --git a/library/server/ewsgi/specification/request/wgi_value.e b/library/server/ewsgi/specification/request/wgi_value.e
index 2919df74..3cb52624 100644
--- a/library/server/ewsgi/specification/request/wgi_value.e
+++ b/library/server/ewsgi/specification/request/wgi_value.e
@@ -7,6 +7,9 @@ note
deferred class
WGI_VALUE
+inherit
+ DEBUG_OUTPUT
+
convert
as_string: {READABLE_STRING_32, STRING_32}
@@ -29,6 +32,14 @@ feature -- Helper
deferred
end
+feature -- Status report
+
+ debug_output: STRING
+ -- String that should be displayed in debugger to represent `Current'.
+ do
+ create Result.make_from_string (name.as_string_8 + "=" + as_string.as_string_8)
+ end
+
feature -- Query
as_string: STRING_32
diff --git a/library/server/ewsgi/src/request/wgi_request_from_table.e b/library/server/ewsgi/src/request/wgi_request_from_table.e
index 3a819e2a..ec6fdb0d 100644
--- a/library/server/ewsgi/src/request/wgi_request_from_table.e
+++ b/library/server/ewsgi/src/request/wgi_request_from_table.e
@@ -114,13 +114,13 @@ feature {NONE} -- Initialization
if attached request_uri as rq_uri then
p := rq_uri.index_of ('?', 1)
if p > 0 then
- set_meta_string_variable (rq_uri.substring (1, p-1), {WGI_META_NAMES}.self)
+ set_meta_string_variable ({WGI_META_NAMES}.self, rq_uri.substring (1, p-1))
else
- set_meta_string_variable (rq_uri, {WGI_META_NAMES}.self)
+ set_meta_string_variable ({WGI_META_NAMES}.self, rq_uri)
end
end
if meta_variable ({WGI_META_NAMES}.request_time) = Void then
- set_meta_string_variable (date_time_utilities.unix_time_stamp (Void).out, {WGI_META_NAMES}.request_time)
+ set_meta_string_variable ({WGI_META_NAMES}.request_time, date_time_utilities.unix_time_stamp (Void).out)
end
end
@@ -185,14 +185,6 @@ feature -- Access: CGI meta parameters
Result := meta_variables_table.item (a_name)
end
- meta_string_variable (a_name: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
- -- CGI meta variable related to `a_name'
- do
- if attached meta_variables_table.item (a_name) as val then
- Result := val.as_string
- end
- end
-
meta_string_variable_or_default (a_name: READABLE_STRING_GENERAL; a_default: READABLE_STRING_32; use_default_when_empty: BOOLEAN): READABLE_STRING_32
-- Value for meta parameter `a_name'
-- If not found, return `a_default'
diff --git a/library/server/request/rest/src/rest_request_handler.e b/library/server/request/rest/src/rest_request_handler.e
index 6f3c8bc6..1660f996 100644
--- a/library/server/request/rest/src/rest_request_handler.e
+++ b/library/server/request/rest/src/rest_request_handler.e
@@ -23,7 +23,7 @@ feature -- Access
end
description: detachable STRING
- -- Optional descriptiong
+ -- Optional description
feature -- Element change
@@ -42,7 +42,7 @@ feature -- Execution
do
if not rescued then
if request_method_name_supported (req.request_method) then
- if authentication_required (req) and then not ctx.authenticated then
+ if authentication_required (req) and then not authenticated (ctx) then
execute_unauthorized (ctx, req, res)
else
pre_execute (ctx, req, res)
@@ -83,6 +83,15 @@ feature -- Execution
res.write_header ({HTTP_STATUS_CODE}.unauthorized, Void)
res.write_string ("Unauthorized")
end
+
+feature -- Auth
+
+ authenticated (ctx: C): BOOLEAN
+ -- Is authenticated?
+ do
+ --| To redefine if needed
+ end
+
feature {NONE} -- Implementation
supported_formats: INTEGER
diff --git a/library/server/request/rest/src/rest_request_handler_context.e b/library/server/request/rest/src/rest_request_handler_context.e
index 4fbf9913..8697bca5 100644
--- a/library/server/request/rest/src/rest_request_handler_context.e
+++ b/library/server/request/rest/src/rest_request_handler_context.e
@@ -54,17 +54,6 @@ feature -- Status report
result_attached: Result /= Void
end
- authenticated: BOOLEAN
- do
- if request.http_authorization /= Void then
- Result := True
- end
- end
-
- authenticated_identifier: detachable READABLE_STRING_32
- do
- end
-
note
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
diff --git a/library/server/request/rest/src/uri/rest_request_uri_routing_handler_i.e b/library/server/request/rest/src/uri/rest_request_uri_routing_handler_i.e
index 86c23462..badbe29d 100644
--- a/library/server/request/rest/src/uri/rest_request_uri_routing_handler_i.e
+++ b/library/server/request/rest/src/uri/rest_request_uri_routing_handler_i.e
@@ -31,7 +31,7 @@ feature -- Execution
execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
do
- Precursor {REST_REQUEST_HANDLER} (ctx, req, res)
+ Precursor {REQUEST_URI_ROUTING_HANDLER_I} (ctx, req, res)
end
execute_application (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
diff --git a/library/server/request/rest/src/uri_template/rest_request_uri_template_routing_handler_i.e b/library/server/request/rest/src/uri_template/rest_request_uri_template_routing_handler_i.e
index 3cece40b..4dea0a26 100644
--- a/library/server/request/rest/src/uri_template/rest_request_uri_template_routing_handler_i.e
+++ b/library/server/request/rest/src/uri_template/rest_request_uri_template_routing_handler_i.e
@@ -38,7 +38,7 @@ feature -- Execution
execute (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
do
- Precursor {REST_REQUEST_HANDLER} (ctx, req, res)
+ Precursor {REQUEST_URI_TEMPLATE_ROUTING_HANDLER_I} (ctx, req, res)
end
execute_application (ctx: C; req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
diff --git a/library/server/request/rest/tests/sample.ecf b/library/server/request/rest/tests/sample.ecf
index 05cfaeab..31ca8469 100644
--- a/library/server/request/rest/tests/sample.ecf
+++ b/library/server/request/rest/tests/sample.ecf
@@ -18,7 +18,7 @@
-
+
/gateway$
diff --git a/library/server/request/router/router-safe.ecf b/library/server/request/router/router-safe.ecf
index eba5a022..f7aff5b6 100644
--- a/library/server/request/router/router-safe.ecf
+++ b/library/server/request/router/router-safe.ecf
@@ -24,7 +24,7 @@
/EIFGENs$
/.svn$
-
diff --git a/library/server/request/router/router.ecf b/library/server/request/router/router.ecf
index b336e855..93fae79f 100644
--- a/library/server/request/router/router.ecf
+++ b/library/server/request/router/router.ecf
@@ -24,7 +24,7 @@
/EIFGENs$
/.svn$
-
diff --git a/library/server/request/router/src/misc/request_handler_routes_recorder.e b/library/server/request/router/src/misc/request_handler_routes_recorder.e
new file mode 100644
index 00000000..80e8be62
--- /dev/null
+++ b/library/server/request/router/src/misc/request_handler_routes_recorder.e
@@ -0,0 +1,44 @@
+note
+ description: "[
+ Summary description for REQUEST_HANDLER_ROUTES_RECORDER.
+
+ You can inherit from this class from any REQUEST_HANDLER and redefine `on_handler_mapped'
+ to record the available routes if your handler needs it.
+ ]"
+ author: ""
+ date: "$Date$"
+ revision: "$Revision$"
+
+deferred class
+ REQUEST_HANDLER_ROUTES_RECORDER
+
+feature {REQUEST_HANDLER} -- Routes access
+
+ available_routes: detachable LIST [TUPLE [resource: READABLE_STRING_8; rqst_methods: detachable ARRAY [READABLE_STRING_8]]]
+ -- Available routes
+
+feature {REQUEST_ROUTER} -- Routes change
+
+ on_handler_mapped (a_resource: READABLE_STRING_8; a_rqst_methods: detachable ARRAY [READABLE_STRING_8])
+ local
+ l_routes: like available_routes
+ do
+ l_routes := available_routes
+ if l_routes = Void then
+ create {ARRAYED_LIST [like available_routes.item]} l_routes.make (3)
+ available_routes := l_routes
+ end
+ l_routes.force ([a_resource, a_rqst_methods])
+ end
+
+note
+ copyright: "2011-2011, Eiffel Software and others"
+ license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
+ source: "[
+ Eiffel Software
+ 5949 Hollister Ave., Goleta, CA 93117 USA
+ Telephone 805-685-1006, Fax 805-685-6869
+ Website http://www.eiffel.com
+ Customer support http://support.eiffel.com
+ ]"
+end
diff --git a/library/server/request/router/src/request_handler.e b/library/server/request/router/src/request_handler.e
index 30f0fc54..76ba939b 100644
--- a/library/server/request/router/src/request_handler.e
+++ b/library/server/request/router/src/request_handler.e
@@ -65,6 +65,13 @@ feature -- Execution: report
result_attached: Result /= Void
end
+feature {REQUEST_ROUTER} -- Routes change
+
+ on_handler_mapped (a_resource: READABLE_STRING_8; a_rqst_methods: detachable ARRAY [READABLE_STRING_8])
+ -- Callback called when a router map a route to Current handler
+ do
+ end
+
note
copyright: "2011-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
diff --git a/library/server/request/router/src/request_handler_context.e b/library/server/request/router/src/request_handler_context.e
index 1e4f0f4f..bfb16b39 100644
--- a/library/server/request/router/src/request_handler_context.e
+++ b/library/server/request/router/src/request_handler_context.e
@@ -98,6 +98,8 @@ feature -- Query
end
i := i + 1
end
+ else
+ Result := s
end
l_accept_lst.forth
end
diff --git a/library/server/request/router/src/uri/request_uri_router_i.e b/library/server/request/router/src/uri/request_uri_router_i.e
index b699f6c0..c82b2089 100644
--- a/library/server/request/router/src/uri/request_uri_router_i.e
+++ b/library/server/request/router/src/uri/request_uri_router_i.e
@@ -26,6 +26,7 @@ feature -- Registration
map_with_request_methods (p: READABLE_STRING_8; h: H; rqst_methods: detachable ARRAY [READABLE_STRING_8])
do
handlers.force ([h, p, formatted_request_methods (rqst_methods)])
+ h.on_handler_mapped (p, rqst_methods)
end
feature {NONE} -- Access: Implementation
diff --git a/library/server/request/router/src/uri_template/request_uri_template_router_i.e b/library/server/request/router/src/uri_template/request_uri_template_router_i.e
index d2f61c4d..e43e1935 100644
--- a/library/server/request/router/src/uri_template/request_uri_template_router_i.e
+++ b/library/server/request/router/src/uri_template/request_uri_template_router_i.e
@@ -33,6 +33,7 @@ feature -- Registration
do
handlers.force ([h, uri.template, formatted_request_methods (rqst_methods)])
templates.force (uri, uri.template)
+ h.on_handler_mapped (uri.template, rqst_methods)
end
map_with_request_methods (tpl: READABLE_STRING_8; h: H; rqst_methods: detachable ARRAY [READABLE_STRING_8])
@@ -53,7 +54,7 @@ feature {NONE} -- Access: Implementation
l_req_method: READABLE_STRING_GENERAL
l_res: URI_TEMPLATE_MATCH_RESULT
do
- p := req.request_uri
+ p := req.path_info
from
l_req_method := req.request_method
l_handlers := handlers
diff --git a/library/text/encoder/src/encoder.e b/library/text/encoder/src/encoder.e
index 52cfa047..daec5d7b 100644
--- a/library/text/encoder/src/encoder.e
+++ b/library/text/encoder/src/encoder.e
@@ -6,7 +6,7 @@ note
revision: "$Revision$"
deferred class
- ENCODER [U -> STRING_GENERAL, E -> STRING_GENERAL] --| U:unencoded type, E:encoded type
+ ENCODER [U -> READABLE_STRING_GENERAL, E -> READABLE_STRING_GENERAL] --| U:unencoded type, E:encoded type
feature -- Access
diff --git a/library/text/encoder/src/url_encoder.e b/library/text/encoder/src/url_encoder.e
index b5370e49..26a0c832 100644
--- a/library/text/encoder/src/url_encoder.e
+++ b/library/text/encoder/src/url_encoder.e
@@ -13,7 +13,7 @@ class
URL_ENCODER
inherit
- ENCODER [STRING_32, STRING_8]
+ ENCODER [READABLE_STRING_32, READABLE_STRING_8]
PLATFORM
export
@@ -30,48 +30,17 @@ feature -- Status report
feature -- Encoder
- encoded_string (s: STRING_32): STRING_8
+ encoded_string (s: READABLE_STRING_32): READABLE_STRING_8
-- URL-encoded value of `s'.
local
i, n: INTEGER
uc: CHARACTER_32
c: CHARACTER_8
+ s8: STRING_8
do
has_error := False
- create Result.make (s.count + s.count // 10)
- n := s.count
- from i := 1 until i > n loop
- uc := s.item (i)
- if uc.is_character_8 then
- c := uc.to_character_8
- inspect c
- when
- 'A' .. 'Z',
- 'a' .. 'z', '0' .. '9',
- '.', '-', '~', '_'
- then
- Result.extend (c)
- when ' ' then
- Result.extend ('+')
- else
- Result.append (url_encoded_char (uc))
- end
- else
- Result.append (url_encoded_char (uc))
- end
- i := i + 1
- end
- end
-
- partial_encoded_string (s: STRING_32; a_ignore: ARRAY [CHARACTER]): STRING_8
- -- URL-encoded value of `s'.
- local
- i, n: INTEGER
- uc: CHARACTER_32
- c: CHARACTER_8
- do
- has_error := False
- create Result.make (s.count + s.count // 10)
+ create s8.make (s.count + s.count // 10)
+ Result := s8
n := s.count
from i := 1 until i > n loop
uc := s.item (i)
@@ -83,21 +52,56 @@ feature -- Encoder
'a' .. 'z', '0' .. '9',
'.', '-', '~', '_'
then
- Result.extend (c)
+ s8.extend (c)
when ' ' then
- Result.extend ('+')
+ s8.extend ('+')
+ else
+ s8.append (url_encoded_char (uc))
+ end
+ else
+ s8.append (url_encoded_char (uc))
+ end
+ i := i + 1
+ end
+ end
+
+ partial_encoded_string (s: READABLE_STRING_32; a_ignore: ARRAY [CHARACTER]): READABLE_STRING_8
+ -- URL-encoded value of `s'.
+ local
+ i, n: INTEGER
+ uc: CHARACTER_32
+ c: CHARACTER_8
+ s8: STRING_8
+ do
+ has_error := False
+ create s8.make (s.count + s.count // 10)
+ Result := s8
+ n := s.count
+ from i := 1 until i > n loop
+ uc := s.item (i)
+ if uc.is_character_8 then
+ c := uc.to_character_8
+ inspect c
+ when
+ 'A' .. 'Z',
+ 'a' .. 'z', '0' .. '9',
+ '.', '-', '~', '_'
+ then
+ s8.extend (c)
+ when ' ' then
+ s8.extend ('+')
else
if a_ignore.has (c) then
- Result.extend (c)
+ s8.extend (c)
else
- Result.append (url_encoded_char (uc))
+ s8.append (url_encoded_char (uc))
end
end
else
if a_ignore.has (c) then
- Result.extend (c)
+ s8.extend (c)
else
- Result.append (url_encoded_char (uc))
+ s8.append (url_encoded_char (uc))
end
end
i := i + 1
@@ -127,33 +131,35 @@ feature {NONE} -- encoder character
feature -- Decoder
- decoded_string (v: STRING_8): STRING_32
+ decoded_string (v: READABLE_STRING_8): READABLE_STRING_32
-- The URL-encoded equivalent of the given string
local
i, n: INTEGER
c: CHARACTER
pr: CELL [INTEGER]
+ s32: STRING_32
do
n := v.count
- create Result.make (n)
+ create s32.make (n)
+ Result := s32
from i := 1
until i > n
loop
c := v.item (i)
inspect c
when '+' then
- Result.append_character ({CHARACTER_32}' ')
+ s32.append_character ({CHARACTER_32}' ')
when '%%' then
-- An escaped character ?
if i = n then
- Result.append_character (c.to_character_32)
+ s32.append_character (c.to_character_32)
else
create pr.put (i)
- Result.append (url_decoded_char (v, pr))
+ s32.append (url_decoded_char (v, pr))
i := pr.item
end
else
- Result.append_character (c.to_character_32)
+ s32.append_character (c.to_character_32)
end
i := i + 1
end