Merge remote-tracking branch 'jocelynEWF/master'
This commit is contained in:
@@ -1,9 +1,28 @@
|
|||||||
History for Eiffel-Web-Framework
|
History for Eiffel-Web-Framework
|
||||||
|
|
||||||
|
[2011-09-23] Jocelyn
|
||||||
|
* library "ewsgi":
|
||||||
|
- NEW simple autotest cases using Nino web server
|
||||||
|
-fixed issue with RAW_POST_DATA being added in form_data_parameters
|
||||||
|
instead of meta_variables ...
|
||||||
|
- Implemented WGI_VALUE for parameter's type (query_parameter,
|
||||||
|
form_data_parameter, item ...)
|
||||||
|
* Nino connector: added feature to shutdown the server from the WGI application
|
||||||
|
* NEW library "http_client": a new library to perform simple http requests
|
||||||
|
such as get, head, post, put, ... (currently implemented with Eiffel cURL)
|
||||||
|
* NEW library "http_authorization": added simple library to support
|
||||||
|
HTTP_AUTHORIZATION. For now only "Basic" auth type is supported ..
|
||||||
|
|
||||||
|
[2011-09-22] Javier
|
||||||
|
* NEW Example: added partial Restbuck example
|
||||||
|
|
||||||
|
[2011-09-21] Jocelyn
|
||||||
|
* Nino connector: fixed an issue with missing value for Content-Type and Content-Length
|
||||||
|
|
||||||
[2011-09-13] Jocelyn
|
[2011-09-13] Jocelyn
|
||||||
* library "router": now using a generic design to allow customization of
|
* library "router": now using a generic design to allow customization of
|
||||||
request handler context class.
|
request handler context class.
|
||||||
* library "server/request/rest": first attempt to provide a library to
|
* NEW library "server/request/rest": first attempt to provide a library to
|
||||||
help building RESTful application (the interfaces are likely to change
|
help building RESTful application (the interfaces are likely to change
|
||||||
soon) EXPERIMENTAL
|
soon) EXPERIMENTAL
|
||||||
|
|
||||||
|
|||||||
2
doc/wiki
2
doc/wiki
Submodule doc/wiki updated: a2a1f89299...820bd7bd6f
@@ -30,6 +30,8 @@ feature {NONE} -- Initialization
|
|||||||
|
|
||||||
create_router
|
create_router
|
||||||
do
|
do
|
||||||
|
-- (create {EXCEPTIONS}).raise ("ouch")
|
||||||
|
check False end
|
||||||
create router.make (5)
|
create router.make (5)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -75,10 +77,10 @@ feature -- Execution
|
|||||||
n: INTEGER
|
n: INTEGER
|
||||||
i: INTEGER
|
i: INTEGER
|
||||||
do
|
do
|
||||||
create h.make
|
|
||||||
l_url := req.script_url ("/home")
|
l_url := req.script_url ("/home")
|
||||||
n := 3
|
n := 3
|
||||||
h.put_refresh (l_url, 5, 200)
|
create h.make
|
||||||
|
h.put_refresh (l_url, 5)
|
||||||
res.set_status_code (200)
|
res.set_status_code (200)
|
||||||
res.write_headers_string (h.string)
|
res.write_headers_string (h.string)
|
||||||
from
|
from
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ feature -- Execution
|
|||||||
create h.make
|
create h.make
|
||||||
l_url := req.script_url ("/home")
|
l_url := req.script_url ("/home")
|
||||||
n := 3
|
n := 3
|
||||||
h.put_refresh (l_url, 5, 200)
|
h.put_refresh (l_url, 5)
|
||||||
res.set_status_code (200)
|
res.set_status_code (200)
|
||||||
res.write_headers_string (h.string)
|
res.write_headers_string (h.string)
|
||||||
from
|
from
|
||||||
|
|||||||
Submodule ext/server/nino updated: 58767bb1c1...9fef2d71f0
1
library/client/http_client/README.md
Normal file
1
library/client/http_client/README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Simple HTTP client implemented using Eiffel cURL library
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
<exclude>/EIFGENs$</exclude>
|
<exclude>/EIFGENs$</exclude>
|
||||||
<exclude>/.svn$</exclude>
|
<exclude>/.svn$</exclude>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<option warning="true" full_class_checking="true" void_safety="none" syntax="standard">
|
<option warning="true" full_class_checking="true" void_safety="none" syntax="provisional">
|
||||||
</option>
|
</option>
|
||||||
<library name="base" location="$ISE_LIBRARY/library/base/base.ecf"/>
|
<library name="base" location="$ISE_LIBRARY/library/base/base.ecf"/>
|
||||||
<library name="cURL" location="$ISE_LIBRARY/library/cURL/cURL.ecf"/>
|
<library name="cURL" location="$ISE_LIBRARY/library/cURL/cURL.ecf"/>
|
||||||
|
|||||||
@@ -21,6 +21,17 @@ feature {NONE} -- Initialization
|
|||||||
|
|
||||||
feature -- Status
|
feature -- Status
|
||||||
|
|
||||||
|
error_occurred: BOOLEAN
|
||||||
|
-- Error occurred during request
|
||||||
|
|
||||||
|
feature {HTTP_CLIENT_REQUEST} -- Status setting
|
||||||
|
|
||||||
|
set_error_occurred (b: BOOLEAN)
|
||||||
|
-- Set `error_occurred' to `b'
|
||||||
|
do
|
||||||
|
error_occurred := b
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
status: INTEGER assign set_status
|
status: INTEGER assign set_status
|
||||||
|
|||||||
@@ -108,6 +108,11 @@ feature -- Change
|
|||||||
timeout := n
|
timeout := n
|
||||||
end
|
end
|
||||||
|
|
||||||
|
set_connect_timeout (n: like connect_timeout)
|
||||||
|
do
|
||||||
|
connect_timeout := n
|
||||||
|
end
|
||||||
|
|
||||||
set_user_agent (v: READABLE_STRING_8)
|
set_user_agent (v: READABLE_STRING_8)
|
||||||
do
|
do
|
||||||
add_header ("User-Agent", v)
|
add_header ("User-Agent", v)
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ inherit
|
|||||||
session
|
session
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
create
|
create
|
||||||
make
|
make
|
||||||
|
|
||||||
@@ -174,19 +173,20 @@ feature -- Execution
|
|||||||
create Result.make
|
create Result.make
|
||||||
l_result := curl_easy.perform (curl_handle)
|
l_result := curl_easy.perform (curl_handle)
|
||||||
|
|
||||||
create a_data.put (Void)
|
if l_result = {CURL_CODES}.curle_ok then
|
||||||
l_result := curl_easy.getinfo (curl_handle, {CURL_INFO_CONSTANTS}.curlinfo_response_code, a_data)
|
create a_data.put (Void)
|
||||||
if l_result = 0 and then attached {INTEGER} a_data.item as l_http_status then
|
l_result := curl_easy.getinfo (curl_handle, {CURL_INFO_CONSTANTS}.curlinfo_response_code, a_data)
|
||||||
Result.status := l_http_status
|
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
|
||||||
|
Result.body := l_curl_string.string
|
||||||
else
|
else
|
||||||
Result.status := 0
|
Result.set_error_occurred (True)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- last_api_call := l_url
|
|
||||||
curl_easy.cleanup (curl_handle)
|
curl_easy.cleanup (curl_handle)
|
||||||
|
|
||||||
|
|
||||||
Result.body := l_curl_string.string
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,42 +7,87 @@ note
|
|||||||
class
|
class
|
||||||
HTTP_AUTHORIZATION
|
HTTP_AUTHORIZATION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
REFACTORING_HELPER
|
||||||
|
|
||||||
create
|
create
|
||||||
make
|
make,
|
||||||
|
make_basic_auth,
|
||||||
|
make_custom_auth
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
make (a_http_authorization: detachable READABLE_STRING_GENERAL)
|
make (a_http_authorization: detachable READABLE_STRING_GENERAL)
|
||||||
-- Initialize `Current'.
|
-- Initialize `Current'.
|
||||||
local
|
local
|
||||||
p: INTEGER
|
i: INTEGER
|
||||||
s: STRING_8
|
t, s: STRING_8
|
||||||
|
u,p: READABLE_STRING_8
|
||||||
do
|
do
|
||||||
if attached a_http_authorization as l_auth then
|
if attached a_http_authorization as l_auth then
|
||||||
s := l_auth.as_string_8
|
s := l_auth.as_string_8
|
||||||
if not s.is_empty then
|
if not s.is_empty then
|
||||||
p := 1
|
i := 1
|
||||||
if s[p] = ' ' then
|
if s[i] = ' ' then
|
||||||
p := p + 1
|
i := i + 1
|
||||||
end
|
end
|
||||||
p := s.index_of (' ', p)
|
i := s.index_of (' ', i)
|
||||||
if p > 0 then
|
if i > 0 then
|
||||||
s := (create {BASE64}).decoded_string (s.substring (p + 1, s.count))
|
t := s.substring (1, i - 1).as_lower
|
||||||
p := s.index_of (':', 1) --| Let's assume ':' is forbidden in login ...
|
t.right_adjust; t.left_adjust
|
||||||
if p > 0 then
|
type := t
|
||||||
login := s.substring (1, p - 1).as_string_32
|
if t.same_string ("basic") then
|
||||||
password := s.substring (p + 1, s.count).as_string_32
|
s := (create {BASE64}).decoded_string (s.substring (i + 1, s.count))
|
||||||
|
i := s.index_of (':', 1) --| Let's assume ':' is forbidden in login ...
|
||||||
|
if i > 0 then
|
||||||
|
u := s.substring (1, i - 1).as_string_32
|
||||||
|
p := s.substring (i + 1, s.count).as_string_32
|
||||||
|
login := u
|
||||||
|
password := p
|
||||||
|
check
|
||||||
|
(create {HTTP_AUTHORIZATION}.make_custom_auth (u, p, t)).http_authorization ~ http_authorization
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif t.same_string ("digest") then
|
||||||
|
to_implement ("HTTP Authorization %"digest%", not yet implemented")
|
||||||
|
else
|
||||||
|
to_implement ("HTTP Authorization %""+ t +"%", not yet implemented")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
make_basic_auth (u: READABLE_STRING_32; p: READABLE_STRING_32)
|
||||||
|
do
|
||||||
|
make_custom_auth (u, p, "basic")
|
||||||
|
end
|
||||||
|
|
||||||
|
make_custom_auth (u: READABLE_STRING_32; p: READABLE_STRING_32; a_type: READABLE_STRING_8)
|
||||||
|
local
|
||||||
|
t: STRING_8
|
||||||
|
do
|
||||||
|
login := u
|
||||||
|
password := p
|
||||||
|
create t.make_from_string (a_type.as_lower)
|
||||||
|
t.left_adjust; t.right_adjust
|
||||||
|
type := t
|
||||||
|
if t.same_string ("basic") then
|
||||||
|
http_authorization := "Basic " + (create {BASE64}).encoded_string (u + ":" + p)
|
||||||
|
else
|
||||||
|
to_implement ("HTTP Authorization %""+ t +"%", not yet implemented")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
|
type: detachable READABLE_STRING_8
|
||||||
|
|
||||||
login: detachable READABLE_STRING_32
|
login: detachable READABLE_STRING_32
|
||||||
|
|
||||||
password: detachable READABLE_STRING_32
|
password: detachable READABLE_STRING_32
|
||||||
|
|
||||||
|
http_authorization: detachable READABLE_STRING_32
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -53,6 +53,12 @@ feature -- Server
|
|||||||
connector.launch
|
connector.launch
|
||||||
end
|
end
|
||||||
|
|
||||||
|
shutdown
|
||||||
|
-- Shutdown the server
|
||||||
|
do
|
||||||
|
connector.server.shutdown_server
|
||||||
|
end
|
||||||
|
|
||||||
note
|
note
|
||||||
copyright: "2011-2011, Eiffel Software and others"
|
copyright: "2011-2011, 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)"
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ inherit
|
|||||||
|
|
||||||
create
|
create
|
||||||
make_with_value,
|
make_with_value,
|
||||||
|
make_with_array,
|
||||||
make_with_string
|
make_with_string
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
feature {NONE} -- Initialization
|
||||||
@@ -25,6 +26,26 @@ feature {NONE} -- Initialization
|
|||||||
add_value (a_value)
|
add_value (a_value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
make_with_array (arr: ARRAY [WGI_VALUE])
|
||||||
|
require
|
||||||
|
arr_not_empty: not arr.is_empty
|
||||||
|
all_same_name: across arr as c all c.item.name.same_string (arr[arr.lower].name) end
|
||||||
|
local
|
||||||
|
i,up: INTEGER
|
||||||
|
do
|
||||||
|
up := arr.upper
|
||||||
|
i := arr.lower
|
||||||
|
make_with_value (arr[i])
|
||||||
|
from
|
||||||
|
i := i + 1
|
||||||
|
until
|
||||||
|
i > up
|
||||||
|
loop
|
||||||
|
add_value (arr[i])
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
make_with_string (a_name: like name; a_string: READABLE_STRING_32)
|
make_with_string (a_name: like name; a_string: READABLE_STRING_32)
|
||||||
do
|
do
|
||||||
make_with_value (create {WGI_STRING_VALUE}.make (a_name, a_string))
|
make_with_value (create {WGI_STRING_VALUE}.make (a_name, a_string))
|
||||||
@@ -75,7 +96,7 @@ feature -- Helper
|
|||||||
across
|
across
|
||||||
string_values as c
|
string_values as c
|
||||||
loop
|
loop
|
||||||
if Result.count = 1 then
|
if Result.count > 1 then
|
||||||
Result.append_character (',')
|
Result.append_character (',')
|
||||||
end
|
end
|
||||||
Result.append_string (c.item)
|
Result.append_string (c.item)
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ feature -- Access: CGI meta variables
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
meta_variables: ITERATION_CURSOR [WGI_VALUE]
|
meta_variables: ITERABLE [WGI_VALUE]
|
||||||
-- These variables are specific to requests made with HTTP.
|
-- These variables are specific to requests made with HTTP.
|
||||||
-- Interpretation of these variables may depend on the value of
|
-- Interpretation of these variables may depend on the value of
|
||||||
-- SERVER_PROTOCOL.
|
-- SERVER_PROTOCOL.
|
||||||
@@ -587,7 +587,7 @@ feature -- Extra CGI environment variables
|
|||||||
|
|
||||||
feature -- Query string Parameters
|
feature -- Query string Parameters
|
||||||
|
|
||||||
query_parameters: ITERATION_CURSOR [WGI_VALUE]
|
query_parameters: ITERABLE [WGI_VALUE]
|
||||||
-- Variables extracted from QUERY_STRING
|
-- Variables extracted from QUERY_STRING
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
@@ -601,7 +601,7 @@ feature -- Query string Parameters
|
|||||||
|
|
||||||
feature -- Form fields and related
|
feature -- Form fields and related
|
||||||
|
|
||||||
form_data_parameters: ITERATION_CURSOR [WGI_VALUE]
|
form_data_parameters: ITERABLE [WGI_VALUE]
|
||||||
-- Variables sent by POST request
|
-- Variables sent by POST request
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
@@ -626,7 +626,7 @@ feature -- Form fields and related
|
|||||||
|
|
||||||
feature -- Cookies
|
feature -- Cookies
|
||||||
|
|
||||||
cookies: ITERATION_CURSOR [WGI_VALUE]
|
cookies: ITERABLE [WGI_VALUE]
|
||||||
-- Expanded cookies variable
|
-- Expanded cookies variable
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
@@ -638,7 +638,7 @@ feature -- Cookies
|
|||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Access: global variable
|
feature -- Access: all variables
|
||||||
|
|
||||||
parameters: like items
|
parameters: like items
|
||||||
obsolete "use items"
|
obsolete "use items"
|
||||||
@@ -652,7 +652,7 @@ feature -- Access: global variable
|
|||||||
Result := item (a_name)
|
Result := item (a_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
items: ITERATION_CURSOR [WGI_VALUE]
|
items: ITERABLE [WGI_VALUE]
|
||||||
-- Table containing all the various variables
|
-- Table containing all the various variables
|
||||||
-- Warning: this is computed each time, if you change the content of other containers
|
-- Warning: this is computed each time, if you change the content of other containers
|
||||||
-- this won't update this Result's content, unless you query it again
|
-- this won't update this Result's content, unless you query it again
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ feature -- Status report
|
|||||||
|
|
||||||
feature {WGI_RESPONSE_BUFFER} -- Core output operation
|
feature {WGI_RESPONSE_BUFFER} -- Core output operation
|
||||||
|
|
||||||
write (s: STRING)
|
write (s: READABLE_STRING_8)
|
||||||
-- Send the string `s'
|
-- Send the string `s'
|
||||||
-- this can be used for header and body
|
-- this can be used for header and body
|
||||||
deferred
|
deferred
|
||||||
@@ -69,7 +69,7 @@ feature -- Status setting
|
|||||||
|
|
||||||
feature -- Header output operation
|
feature -- Header output operation
|
||||||
|
|
||||||
write_headers_string (a_headers: STRING)
|
write_headers_string (a_headers: READABLE_STRING_8)
|
||||||
require
|
require
|
||||||
status_set: status_is_set
|
status_set: status_is_set
|
||||||
header_not_committed: not header_committed
|
header_not_committed: not header_committed
|
||||||
@@ -80,7 +80,7 @@ feature -- Header output operation
|
|||||||
message_writable: message_writable
|
message_writable: message_writable
|
||||||
end
|
end
|
||||||
|
|
||||||
write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]])
|
write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]])
|
||||||
-- Send headers with status `a_status', and headers from `a_headers'
|
-- Send headers with status `a_status', and headers from `a_headers'
|
||||||
require
|
require
|
||||||
status_not_set: not status_is_set
|
status_not_set: not status_is_set
|
||||||
@@ -94,21 +94,21 @@ feature -- Header output operation
|
|||||||
|
|
||||||
feature -- Output operation
|
feature -- Output operation
|
||||||
|
|
||||||
write_string (s: STRING)
|
write_string (s: READABLE_STRING_8)
|
||||||
-- Send the string `s'
|
-- Send the string `s'
|
||||||
require
|
require
|
||||||
message_writable: message_writable
|
message_writable: message_writable
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
write_substring (s: STRING; a_begin_index, a_end_index: INTEGER)
|
write_substring (s: READABLE_STRING_8; a_begin_index, a_end_index: INTEGER)
|
||||||
-- Send the substring `s[a_begin_index:a_end_index]'
|
-- Send the substring `s[a_begin_index:a_end_index]'
|
||||||
require
|
require
|
||||||
message_writable: message_writable
|
message_writable: message_writable
|
||||||
deferred
|
deferred
|
||||||
end
|
end
|
||||||
|
|
||||||
write_file_content (fn: STRING)
|
write_file_content (fn: READABLE_STRING_8)
|
||||||
-- Send the content of file `fn'
|
-- Send the content of file `fn'
|
||||||
require
|
require
|
||||||
message_writable: message_writable
|
message_writable: message_writable
|
||||||
|
|||||||
@@ -16,14 +16,13 @@ feature -- Execution
|
|||||||
execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
-- Execute the request
|
-- Execute the request
|
||||||
-- See `req.input' for input stream
|
-- See `req.input' for input stream
|
||||||
-- `req.environment' for the Gateway environment
|
-- `req.meta_variables' for the CGI meta variable
|
||||||
-- and `res' for output buffer
|
-- and `res' for output buffer
|
||||||
require
|
require
|
||||||
res_status_unset: not res.status_is_set
|
res_status_unset: not res.status_is_set
|
||||||
deferred
|
deferred
|
||||||
ensure
|
ensure
|
||||||
res_status_set: res.status_is_set
|
res_status_set: res.status_is_set
|
||||||
-- res_committed: res.message_committed
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Process request
|
feature -- Process request
|
||||||
|
|||||||
@@ -174,9 +174,9 @@ feature {NONE} -- Access: CGI meta parameters
|
|||||||
|
|
||||||
feature -- Access: CGI meta parameters
|
feature -- Access: CGI meta parameters
|
||||||
|
|
||||||
meta_variables: ITERATION_CURSOR [WGI_VALUE]
|
meta_variables: ITERABLE [WGI_VALUE]
|
||||||
do
|
do
|
||||||
Result := meta_variables_table.new_cursor
|
Result := meta_variables_table
|
||||||
end
|
end
|
||||||
|
|
||||||
meta_variable (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
|
meta_variable (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
|
||||||
@@ -429,9 +429,9 @@ feature {NONE} -- Query parameters
|
|||||||
|
|
||||||
feature -- Query parameters
|
feature -- Query parameters
|
||||||
|
|
||||||
query_parameters: ITERATION_CURSOR [WGI_VALUE]
|
query_parameters: ITERABLE [WGI_VALUE]
|
||||||
do
|
do
|
||||||
Result := query_parameters_table.new_cursor
|
Result := query_parameters_table
|
||||||
end
|
end
|
||||||
|
|
||||||
query_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
|
query_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
|
||||||
@@ -448,6 +448,7 @@ feature {NONE} -- Query parameters: implementation
|
|||||||
n, p, i, j: INTEGER
|
n, p, i, j: INTEGER
|
||||||
s: STRING
|
s: STRING
|
||||||
l_name,l_value: STRING_32
|
l_name,l_value: STRING_32
|
||||||
|
v: WGI_VALUE
|
||||||
do
|
do
|
||||||
if a_content = Void then
|
if a_content = Void then
|
||||||
create Result.make (0)
|
create Result.make (0)
|
||||||
@@ -479,7 +480,17 @@ feature {NONE} -- Query parameters: implementation
|
|||||||
l_name := url_encoder.decoded_string (l_name)
|
l_name := url_encoder.decoded_string (l_name)
|
||||||
l_value := url_encoder.decoded_string (l_value)
|
l_value := url_encoder.decoded_string (l_value)
|
||||||
end
|
end
|
||||||
Result.force (new_string_value (l_name, l_value), l_name)
|
v := new_string_value (l_name, l_value)
|
||||||
|
if Result.has_key (l_name) and then attached Result.found_item as l_existing_value then
|
||||||
|
if attached {WGI_MULTIPLE_STRING_VALUE} l_existing_value as l_multi then
|
||||||
|
l_multi.add_value (v)
|
||||||
|
else
|
||||||
|
Result.force (create {WGI_MULTIPLE_STRING_VALUE}.make_with_array (<<l_existing_value, v>>), l_name)
|
||||||
|
check replaced: Result.found and then Result.found_item ~ l_existing_value end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result.force (v, l_name)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -515,7 +526,7 @@ feature {NONE} -- Form fields and related
|
|||||||
vars := urlencoded_parameters (s, True)
|
vars := urlencoded_parameters (s, True)
|
||||||
end
|
end
|
||||||
if raw_post_data_recorded then
|
if raw_post_data_recorded then
|
||||||
vars.force (new_string_value ("RAW_POST_DATA", s), "RAW_POST_DATA")
|
set_meta_string_variable ("RAW_POST_DATA", s)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
create vars.make (0)
|
create vars.make (0)
|
||||||
@@ -527,9 +538,9 @@ feature {NONE} -- Form fields and related
|
|||||||
|
|
||||||
feature -- Form fields and related
|
feature -- Form fields and related
|
||||||
|
|
||||||
form_data_parameters: ITERATION_CURSOR [WGI_VALUE]
|
form_data_parameters: ITERABLE [WGI_VALUE]
|
||||||
do
|
do
|
||||||
Result := form_data_parameters_table.new_cursor
|
Result := form_data_parameters_table
|
||||||
end
|
end
|
||||||
|
|
||||||
form_data_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
|
form_data_parameter (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
|
||||||
@@ -595,9 +606,9 @@ feature {NONE} -- Cookies
|
|||||||
|
|
||||||
feature -- Cookies
|
feature -- Cookies
|
||||||
|
|
||||||
cookies: ITERATION_CURSOR [WGI_VALUE]
|
cookies: ITERABLE [WGI_VALUE]
|
||||||
do
|
do
|
||||||
Result := cookies_table.new_cursor
|
Result := cookies_table
|
||||||
end
|
end
|
||||||
|
|
||||||
cookie (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
|
cookie (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
|
||||||
@@ -612,57 +623,40 @@ feature {NONE} -- Access: global variable
|
|||||||
-- Table containing all the various variables
|
-- Table containing all the various variables
|
||||||
-- Warning: this is computed each time, if you change the content of other containers
|
-- Warning: this is computed each time, if you change the content of other containers
|
||||||
-- this won't update this Result's content, unless you query it again
|
-- this won't update this Result's content, unless you query it again
|
||||||
local
|
|
||||||
vars: ITERATION_CURSOR [WGI_VALUE]
|
|
||||||
do
|
do
|
||||||
create Result.make (100)
|
create Result.make (100)
|
||||||
|
|
||||||
vars := meta_variables
|
across
|
||||||
from
|
meta_variables as vars
|
||||||
-- vars.start
|
|
||||||
until
|
|
||||||
vars.after
|
|
||||||
loop
|
loop
|
||||||
Result.force (vars.item, vars.item.name)
|
Result.force (vars.item, vars.item.name)
|
||||||
vars.forth
|
|
||||||
end
|
end
|
||||||
|
|
||||||
vars := query_parameters
|
across
|
||||||
from
|
query_parameters as vars
|
||||||
-- vars.start
|
|
||||||
until
|
|
||||||
vars.after
|
|
||||||
loop
|
loop
|
||||||
Result.force (vars.item, vars.item.name)
|
Result.force (vars.item, vars.item.name)
|
||||||
vars.forth
|
|
||||||
end
|
end
|
||||||
|
|
||||||
vars := form_data_parameters
|
across
|
||||||
from
|
form_data_parameters as vars
|
||||||
-- vars.start
|
|
||||||
until
|
|
||||||
vars.after
|
|
||||||
loop
|
loop
|
||||||
Result.force (vars.item, vars.item.name)
|
Result.force (vars.item, vars.item.name)
|
||||||
vars.forth
|
|
||||||
end
|
end
|
||||||
|
|
||||||
vars := cookies
|
across
|
||||||
from
|
cookies as vars
|
||||||
-- vars.start
|
|
||||||
until
|
|
||||||
vars.after
|
|
||||||
loop
|
loop
|
||||||
Result.force (vars.item, vars.item.name)
|
Result.force (vars.item, vars.item.name)
|
||||||
vars.forth
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Access: global variable
|
feature -- Access: global variable
|
||||||
|
|
||||||
items: ITERATION_CURSOR [WGI_VALUE]
|
items: ITERABLE [WGI_VALUE]
|
||||||
do
|
do
|
||||||
Result := items_table.new_cursor
|
Result := items_table
|
||||||
end
|
end
|
||||||
|
|
||||||
item (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
|
item (a_name: READABLE_STRING_GENERAL): detachable WGI_VALUE
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ feature -- Status report
|
|||||||
|
|
||||||
feature {NONE} -- Core output operation
|
feature {NONE} -- Core output operation
|
||||||
|
|
||||||
write (s: STRING)
|
write (s: READABLE_STRING_8)
|
||||||
-- Send the content of `s'
|
-- Send the content of `s'
|
||||||
-- this can be used for header and body
|
-- this can be used for header and body
|
||||||
do
|
do
|
||||||
@@ -76,13 +76,13 @@ feature -- Status setting
|
|||||||
|
|
||||||
feature -- Header output operation
|
feature -- Header output operation
|
||||||
|
|
||||||
write_headers_string (a_headers: STRING)
|
write_headers_string (a_headers: READABLE_STRING_8)
|
||||||
do
|
do
|
||||||
write (a_headers)
|
write (a_headers)
|
||||||
header_committed := True
|
header_committed := True
|
||||||
end
|
end
|
||||||
|
|
||||||
write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]])
|
write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]])
|
||||||
-- Send headers with status `a_status', and headers from `a_headers'
|
-- Send headers with status `a_status', and headers from `a_headers'
|
||||||
local
|
local
|
||||||
h: EWF_HEADER
|
h: EWF_HEADER
|
||||||
@@ -107,20 +107,20 @@ feature -- Header output operation
|
|||||||
|
|
||||||
feature -- Output operation
|
feature -- Output operation
|
||||||
|
|
||||||
write_string (s: STRING)
|
write_string (s: READABLE_STRING_8)
|
||||||
-- Send the string `s'
|
-- Send the string `s'
|
||||||
do
|
do
|
||||||
write (s)
|
write (s)
|
||||||
end
|
end
|
||||||
|
|
||||||
write_substring (s: STRING; start_index, end_index: INTEGER)
|
write_substring (s: READABLE_STRING_8; start_index, end_index: INTEGER)
|
||||||
-- Send the substring `start_index:end_index]'
|
-- Send the substring `start_index:end_index]'
|
||||||
--| Could be optimized according to the target output
|
--| Could be optimized according to the target output
|
||||||
do
|
do
|
||||||
output.put_substring (s, start_index, end_index)
|
output.put_substring (s, start_index, end_index)
|
||||||
end
|
end
|
||||||
|
|
||||||
write_file_content (fn: STRING)
|
write_file_content (fn: READABLE_STRING_8)
|
||||||
-- Send the content of file `fn'
|
-- Send the content of file `fn'
|
||||||
do
|
do
|
||||||
output.put_file_content (fn)
|
output.put_file_content (fn)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ feature {NONE} -- Initialization
|
|||||||
make
|
make
|
||||||
-- Initialize current
|
-- Initialize current
|
||||||
do
|
do
|
||||||
create {ARRAYED_LIST [STRING]} headers.make (3)
|
create {ARRAYED_LIST [READABLE_STRING_8]} headers.make (3)
|
||||||
end
|
end
|
||||||
|
|
||||||
feature -- Recycle
|
feature -- Recycle
|
||||||
@@ -40,7 +40,7 @@ feature -- Recycle
|
|||||||
|
|
||||||
feature -- Access
|
feature -- Access
|
||||||
|
|
||||||
headers: LIST [STRING]
|
headers: LIST [READABLE_STRING_8]
|
||||||
-- Header's lines
|
-- Header's lines
|
||||||
|
|
||||||
string: STRING
|
string: STRING
|
||||||
@@ -67,24 +67,24 @@ feature -- Access
|
|||||||
|
|
||||||
feature -- Header change: general
|
feature -- Header change: general
|
||||||
|
|
||||||
add_header (h: STRING)
|
add_header (h: READABLE_STRING_8)
|
||||||
do
|
do
|
||||||
headers.force (h)
|
headers.force (h)
|
||||||
end
|
end
|
||||||
|
|
||||||
put_header (h: STRING)
|
put_header (h: READABLE_STRING_8)
|
||||||
-- Add header `h' or replace existing header of same header name
|
-- Add header `h' or replace existing header of same header name
|
||||||
do
|
do
|
||||||
force_header_by_name (header_name (h), h)
|
force_header_by_name (header_name (h), h)
|
||||||
end
|
end
|
||||||
|
|
||||||
add_header_key_value (k,v: STRING)
|
add_header_key_value (k,v: READABLE_STRING_8)
|
||||||
-- Add header `k:v', or replace existing header of same header name/key
|
-- Add header `k:v', or replace existing header of same header name/key
|
||||||
do
|
do
|
||||||
add_header (k + colon_space + v)
|
add_header (k + colon_space + v)
|
||||||
end
|
end
|
||||||
|
|
||||||
put_header_key_value (k,v: STRING)
|
put_header_key_value (k,v: READABLE_STRING_8)
|
||||||
-- Add header `k:v', or replace existing header of same header name/key
|
-- Add header `k:v', or replace existing header of same header name/key
|
||||||
do
|
do
|
||||||
put_header (k + colon_space + v)
|
put_header (k + colon_space + v)
|
||||||
@@ -104,23 +104,23 @@ feature -- Content related header
|
|||||||
put_header_key_value ("Status", s)
|
put_header_key_value ("Status", s)
|
||||||
end
|
end
|
||||||
|
|
||||||
put_content_type (t: STRING)
|
put_content_type (t: READABLE_STRING_8)
|
||||||
do
|
do
|
||||||
put_header_key_value (name_content_type, t)
|
put_header_key_value (name_content_type, t)
|
||||||
end
|
end
|
||||||
|
|
||||||
add_content_type (t: STRING)
|
add_content_type (t: READABLE_STRING_8)
|
||||||
-- same as `put_content_type', but allow multiple definition of "Content-Type"
|
-- same as `put_content_type', but allow multiple definition of "Content-Type"
|
||||||
do
|
do
|
||||||
add_header_key_value (name_content_type, t)
|
add_header_key_value (name_content_type, t)
|
||||||
end
|
end
|
||||||
|
|
||||||
put_content_type_with_name (t: STRING; n: STRING)
|
put_content_type_with_name (t: READABLE_STRING_8; n: READABLE_STRING_8)
|
||||||
do
|
do
|
||||||
put_header_key_value (name_content_type, t + "; name=%"" + n + "%"")
|
put_header_key_value (name_content_type, t + "; name=%"" + n + "%"")
|
||||||
end
|
end
|
||||||
|
|
||||||
add_content_type_with_name (t: STRING; n: STRING)
|
add_content_type_with_name (t: READABLE_STRING_8; n: READABLE_STRING_8)
|
||||||
-- same as `put_content_type_with_name', but allow multiple definition of "Content-Type"
|
-- same as `put_content_type_with_name', but allow multiple definition of "Content-Type"
|
||||||
do
|
do
|
||||||
add_header_key_value (name_content_type, t + "; name=%"" + n + "%"")
|
add_header_key_value (name_content_type, t + "; name=%"" + n + "%"")
|
||||||
@@ -158,7 +158,7 @@ feature -- Content related header
|
|||||||
put_header_key_value (name_content_length, n.out)
|
put_header_key_value (name_content_length, n.out)
|
||||||
end
|
end
|
||||||
|
|
||||||
put_content_transfer_encoding (a_mechanism: STRING)
|
put_content_transfer_encoding (a_mechanism: READABLE_STRING_8)
|
||||||
-- Put "Content-Transfer-Encoding" header with for instance "binary"
|
-- Put "Content-Transfer-Encoding" header with for instance "binary"
|
||||||
--| encoding := "Content-Transfer-Encoding" ":" mechanism
|
--| encoding := "Content-Transfer-Encoding" ":" mechanism
|
||||||
--|
|
--|
|
||||||
@@ -173,7 +173,7 @@ feature -- Content related header
|
|||||||
put_header_key_value ("Content-Transfer-Encoding", a_mechanism)
|
put_header_key_value ("Content-Transfer-Encoding", a_mechanism)
|
||||||
end
|
end
|
||||||
|
|
||||||
put_content_disposition (a_type: STRING; a_params: detachable STRING)
|
put_content_disposition (a_type: READABLE_STRING_8; a_params: detachable READABLE_STRING_8)
|
||||||
-- Put "Content-Disposition" header
|
-- Put "Content-Disposition" header
|
||||||
--| See RFC2183
|
--| See RFC2183
|
||||||
--| disposition := "Content-Disposition" ":"
|
--| disposition := "Content-Disposition" ":"
|
||||||
@@ -212,13 +212,13 @@ feature -- Others
|
|||||||
put_header_key_value ("Expires", n.out)
|
put_header_key_value ("Expires", n.out)
|
||||||
end
|
end
|
||||||
|
|
||||||
put_cache_control (s: STRING)
|
put_cache_control (s: READABLE_STRING_8)
|
||||||
-- `s' could be for instance "no-cache, must-revalidate"
|
-- `s' could be for instance "no-cache, must-revalidate"
|
||||||
do
|
do
|
||||||
put_header_key_value ("Cache-Control", s)
|
put_header_key_value ("Cache-Control", s)
|
||||||
end
|
end
|
||||||
|
|
||||||
put_pragma (s: STRING)
|
put_pragma (s: READABLE_STRING_8)
|
||||||
do
|
do
|
||||||
put_header_key_value ("Pragma", s)
|
put_header_key_value ("Pragma", s)
|
||||||
end
|
end
|
||||||
@@ -230,13 +230,13 @@ feature -- Others
|
|||||||
|
|
||||||
feature -- Redirection
|
feature -- Redirection
|
||||||
|
|
||||||
put_redirection (a_location: STRING; a_code: INTEGER)
|
put_location (a_location: READABLE_STRING_8)
|
||||||
-- Tell the client to redirect to page with `a_location' right away
|
-- Tell the client the new location `a_location'
|
||||||
do
|
do
|
||||||
put_header_key_value ("Location", a_location)
|
put_header_key_value ("Location", a_location)
|
||||||
end
|
end
|
||||||
|
|
||||||
put_refresh (a_location: STRING; a_timeout: INTEGER; a_code: INTEGER)
|
put_refresh (a_location: READABLE_STRING_8; a_timeout: INTEGER)
|
||||||
-- Tell the client to refresh page with `a_location' after `a_timeout' in seconds
|
-- Tell the client to refresh page with `a_location' after `a_timeout' in seconds
|
||||||
do
|
do
|
||||||
put_header_key_value ("Refresh", a_timeout.out + "; url=" + a_location)
|
put_header_key_value ("Refresh", a_timeout.out + "; url=" + a_location)
|
||||||
@@ -244,7 +244,7 @@ feature -- Redirection
|
|||||||
|
|
||||||
feature -- Cookie
|
feature -- Cookie
|
||||||
|
|
||||||
put_cookie (key, value: STRING_8; expiration, path, domain, secure: detachable STRING_8)
|
put_cookie (key, value: READABLE_STRING_8; expiration, path, domain, secure: detachable READABLE_STRING_8)
|
||||||
-- Set a cookie on the client's machine
|
-- Set a cookie on the client's machine
|
||||||
-- with key 'key' and value 'value'.
|
-- with key 'key' and value 'value'.
|
||||||
require
|
require
|
||||||
@@ -270,7 +270,7 @@ feature -- Cookie
|
|||||||
|
|
||||||
feature -- Status report
|
feature -- Status report
|
||||||
|
|
||||||
has_header_named (a_name: STRING): BOOLEAN
|
has_header_named (a_name: READABLE_STRING_8): BOOLEAN
|
||||||
-- Has header item for `n'?
|
-- Has header item for `n'?
|
||||||
local
|
local
|
||||||
c: like headers.new_cursor
|
c: like headers.new_cursor
|
||||||
@@ -295,7 +295,7 @@ feature -- Status report
|
|||||||
|
|
||||||
feature {NONE} -- Implementation: Header
|
feature {NONE} -- Implementation: Header
|
||||||
|
|
||||||
force_header_by_name (n: detachable STRING; h: STRING)
|
force_header_by_name (n: detachable READABLE_STRING_8; h: READABLE_STRING_8)
|
||||||
-- Add header `h' or replace existing header of same header name `n'
|
-- Add header `h' or replace existing header of same header name `n'
|
||||||
require
|
require
|
||||||
h_has_name_n: (n /= Void and attached header_name (h) as hn) implies n.same_string (hn)
|
h_has_name_n: (n /= Void and attached header_name (h) as hn) implies n.same_string (hn)
|
||||||
@@ -321,36 +321,38 @@ feature {NONE} -- Implementation: Header
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
header_name (h: STRING): detachable STRING
|
header_name (h: READABLE_STRING_8): detachable READABLE_STRING_8
|
||||||
-- If any, header's name with colon
|
-- If any, header's name with colon
|
||||||
--| ex: for "Foo-bar: something", this will return "Foo-bar:"
|
--| ex: for "Foo-bar: something", this will return "Foo-bar:"
|
||||||
local
|
local
|
||||||
|
s: detachable STRING_8
|
||||||
i,n: INTEGER
|
i,n: INTEGER
|
||||||
c: CHARACTER
|
c: CHARACTER
|
||||||
do
|
do
|
||||||
from
|
from
|
||||||
i := 1
|
i := 1
|
||||||
n := h.count
|
n := h.count
|
||||||
create Result.make (10)
|
create s.make (10)
|
||||||
until
|
until
|
||||||
i > n or c = ':' or Result = Void
|
i > n or c = ':' or s = Void
|
||||||
loop
|
loop
|
||||||
c := h[i]
|
c := h[i]
|
||||||
inspect c
|
inspect c
|
||||||
when ':' then
|
when ':' then
|
||||||
Result.extend (c)
|
s.extend (c)
|
||||||
when '-', 'a' .. 'z', 'A' .. 'Z' then
|
when '-', 'a' .. 'z', 'A' .. 'Z' then
|
||||||
Result.extend (c)
|
s.extend (c)
|
||||||
else
|
else
|
||||||
Result := Void
|
s := Void
|
||||||
end
|
end
|
||||||
i := i + 1
|
i := i + 1
|
||||||
end
|
end
|
||||||
|
Result := s
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
append_line_to (s, h: STRING)
|
append_line_to (s: READABLE_STRING_8; h: like string)
|
||||||
do
|
do
|
||||||
h.append_string (s)
|
h.append_string (s)
|
||||||
append_end_of_line_to (h)
|
append_end_of_line_to (h)
|
||||||
|
|||||||
208
library/server/ewsgi/tests/test_ewsgi_request.e
Normal file
208
library/server/ewsgi/tests/test_ewsgi_request.e
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Eiffel tests that can be executed by testing tool.
|
||||||
|
]"
|
||||||
|
author: "EiffelStudio test wizard"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
testing: "type/manual"
|
||||||
|
|
||||||
|
class
|
||||||
|
TEST_EWSGI_REQUEST
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EQA_TEST_SET
|
||||||
|
redefine
|
||||||
|
on_prepare,
|
||||||
|
on_clean
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Events
|
||||||
|
|
||||||
|
web_app: detachable NINO_APPLICATION
|
||||||
|
|
||||||
|
port_number: INTEGER
|
||||||
|
base_url: detachable STRING
|
||||||
|
|
||||||
|
on_prepare
|
||||||
|
-- <Precursor>
|
||||||
|
local
|
||||||
|
app: NINO_APPLICATION
|
||||||
|
wt: WORKER_THREAD
|
||||||
|
e: EXECUTION_ENVIRONMENT
|
||||||
|
do
|
||||||
|
port_number := 8087
|
||||||
|
base_url := "test/"
|
||||||
|
create app.make_custom (agent execute, base_url)
|
||||||
|
web_app := app
|
||||||
|
|
||||||
|
create wt.make (agent app.listen (port_number))
|
||||||
|
wt.launch
|
||||||
|
|
||||||
|
create e
|
||||||
|
e.sleep (1_000_000_000 * 5)
|
||||||
|
end
|
||||||
|
|
||||||
|
execute (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER)
|
||||||
|
local
|
||||||
|
q: detachable STRING_32
|
||||||
|
do
|
||||||
|
if attached req.request_uri as l_uri then
|
||||||
|
if l_uri.starts_with (test_url ("get/01")) then
|
||||||
|
res.write_header (200, <<["Content-Type", "text/plain"]>>)
|
||||||
|
res.write_string ("get-01")
|
||||||
|
create q.make_empty
|
||||||
|
|
||||||
|
across
|
||||||
|
req.query_parameters as qcur
|
||||||
|
loop
|
||||||
|
if not q.is_empty then
|
||||||
|
q.append_character ('&')
|
||||||
|
end
|
||||||
|
q.append (qcur.item.name.as_string_32 + "=" + qcur.item.as_string)
|
||||||
|
end
|
||||||
|
if not q.is_empty then
|
||||||
|
res.write_string ("(" + q + ")")
|
||||||
|
end
|
||||||
|
elseif l_uri.starts_with (test_url ("post/01")) then
|
||||||
|
res.write_header (200, <<["Content-Type", "text/plain"]>>)
|
||||||
|
res.write_string ("post-01")
|
||||||
|
create q.make_empty
|
||||||
|
|
||||||
|
across
|
||||||
|
req.query_parameters as qcur
|
||||||
|
loop
|
||||||
|
if not q.is_empty then
|
||||||
|
q.append_character ('&')
|
||||||
|
end
|
||||||
|
q.append (qcur.item.name.as_string_32 + "=" + qcur.item.as_string)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not q.is_empty then
|
||||||
|
res.write_string ("(" + q + ")")
|
||||||
|
end
|
||||||
|
|
||||||
|
create q.make_empty
|
||||||
|
|
||||||
|
|
||||||
|
across
|
||||||
|
req.form_data_parameters as fcur
|
||||||
|
loop
|
||||||
|
if not q.is_empty then
|
||||||
|
q.append_character ('&')
|
||||||
|
end
|
||||||
|
q.append (fcur.item.name.as_string_32 + "=" + fcur.item.as_string)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not q.is_empty then
|
||||||
|
res.write_string (" : " + q )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
res.write_header (200, <<["Content-Type", "text/plain"]>>)
|
||||||
|
res.write_string ("Hello")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
res.write_header (200, <<["Content-Type", "text/plain"]>>)
|
||||||
|
res.write_string ("Bye")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test_url (a_query_url: READABLE_STRING_8): READABLE_STRING_8
|
||||||
|
local
|
||||||
|
b: like base_url
|
||||||
|
do
|
||||||
|
b := base_url
|
||||||
|
if b = Void then
|
||||||
|
b := ""
|
||||||
|
end
|
||||||
|
Result := "/" + b + a_query_url
|
||||||
|
end
|
||||||
|
|
||||||
|
on_clean
|
||||||
|
-- <Precursor>
|
||||||
|
do
|
||||||
|
if attached web_app as app then
|
||||||
|
app.shutdown
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
http_session: detachable HTTP_CLIENT_SESSION
|
||||||
|
|
||||||
|
get_http_session
|
||||||
|
local
|
||||||
|
h: LIBCURL_HTTP_CLIENT
|
||||||
|
b: like base_url
|
||||||
|
do
|
||||||
|
create h.make
|
||||||
|
b := base_url
|
||||||
|
if b = Void then
|
||||||
|
b := ""
|
||||||
|
end
|
||||||
|
if attached {HTTP_CLIENT_SESSION} h.new_session ("localhost:" + port_number.out + "/" + b) as sess then
|
||||||
|
http_session := sess
|
||||||
|
sess.set_timeout (-1)
|
||||||
|
sess.set_connect_timeout (-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test_get_request (a_url: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; a_expected_body: READABLE_STRING_8)
|
||||||
|
do
|
||||||
|
get_http_session
|
||||||
|
if attached http_session as sess then
|
||||||
|
if attached sess.get (a_url, ctx) as res and then not res.error_occurred and then attached res.body as l_body then
|
||||||
|
assert ("Good answer got=%""+l_body+"%" expected=%""+a_expected_body+"%"", l_body.same_string (a_expected_body))
|
||||||
|
else
|
||||||
|
assert ("Request %""+a_url+"%" failed", False)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test_post_request (a_url: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; a_expected_body: READABLE_STRING_8)
|
||||||
|
do
|
||||||
|
get_http_session
|
||||||
|
if attached http_session as sess then
|
||||||
|
if attached sess.post (a_url, ctx) as res and then not res.error_occurred and then attached res.body as l_body then
|
||||||
|
assert ("Good answer got=%""+l_body+"%" expected=%""+a_expected_body+"%"", l_body.same_string (a_expected_body))
|
||||||
|
else
|
||||||
|
assert ("Request %""+a_url+"%" failed", False)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Test routines
|
||||||
|
|
||||||
|
test_get_request_01
|
||||||
|
-- New test routine
|
||||||
|
do
|
||||||
|
get_http_session
|
||||||
|
if attached http_session as sess then
|
||||||
|
test_get_request ("get/01", Void, "get-01")
|
||||||
|
test_get_request ("get/01/?foo=bar", Void, "get-01(foo=bar)")
|
||||||
|
test_get_request ("get/01/?foo=bar&abc=def", Void, "get-01(foo=bar&abc=def)")
|
||||||
|
test_get_request ("get/01/?lst=a&lst=b", Void, "get-01(lst=[a,b])")
|
||||||
|
else
|
||||||
|
assert ("not_implemented", False)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test_post_request_01
|
||||||
|
-- New test routine
|
||||||
|
local
|
||||||
|
ctx: HTTP_CLIENT_REQUEST_CONTEXT
|
||||||
|
do
|
||||||
|
get_http_session
|
||||||
|
if attached http_session as sess then
|
||||||
|
create ctx.make
|
||||||
|
ctx.add_form_data_parameter ("id", "123")
|
||||||
|
test_post_request ("post/01", ctx, "post-01 : id=123")
|
||||||
|
test_post_request ("post/01/?foo=bar", ctx, "post-01(foo=bar) : id=123")
|
||||||
|
test_post_request ("post/01/?foo=bar&abc=def", ctx, "post-01(foo=bar&abc=def) : id=123")
|
||||||
|
test_post_request ("post/01/?lst=a&lst=b", ctx, "post-01(lst=[a,b]) : id=123")
|
||||||
|
else
|
||||||
|
assert ("not_implemented", False)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
21
library/server/ewsgi/tests/tests-safe.ecf
Normal file
21
library/server/ewsgi/tests/tests-safe.ecf
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="tests" uuid="4C432110-F2DA-4D69-B80B-268CC1253B78">
|
||||||
|
<target name="tests">
|
||||||
|
<root class="ANY" feature="default_create"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||||
|
</option>
|
||||||
|
<setting name="concurrency" value="thread"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="ewsgi_nino" location="..\default\ewsgi_nino-safe.ecf" readonly="false"/>
|
||||||
|
<library name="ewsgi" location="..\ewsgi-safe.ecf" readonly="false"/>
|
||||||
|
<library name="http_client" location="..\..\..\client\http_client\http_client-safe.ecf"/>
|
||||||
|
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
||||||
|
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
|
||||||
|
<tests name="src" location=".\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
19
library/server/ewsgi/tests/tests.ecf
Normal file
19
library/server/ewsgi/tests/tests.ecf
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="tests" uuid="4C432110-F2DA-4D69-B80B-268CC1253B78">
|
||||||
|
<target name="tests">
|
||||||
|
<root class="ANY" feature="default_create"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" void_safety="none" syntax="standard">
|
||||||
|
</option>
|
||||||
|
<setting name="concurrency" value="none"/>
|
||||||
|
<library name="ewsgi_spec" location="..\ewsgi_spec.ecf"/>
|
||||||
|
<library name="ewsgi_nino" location="..\default\ewsgi_nino.ecf"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY/library/base/base.ecf"/>
|
||||||
|
<library name="testing" location="$ISE_LIBRARY/library/testing/testing.ecf"/>
|
||||||
|
<tests name="src" location="." recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -25,7 +25,14 @@ create
|
|||||||
|
|
||||||
feature -- Status report
|
feature -- Status report
|
||||||
|
|
||||||
authentication_required: BOOLEAN
|
authentication_required (req: WGI_REQUEST): BOOLEAN
|
||||||
|
do
|
||||||
|
Result := internal_authentication_required
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
internal_authentication_required: BOOLEAN
|
||||||
|
|
||||||
feature -- Execution
|
feature -- Execution
|
||||||
|
|
||||||
|
|||||||
@@ -63,9 +63,9 @@ feature -- Execution
|
|||||||
do
|
do
|
||||||
content_type_supported := <<{HTTP_CONSTANTS}.json_app, {HTTP_CONSTANTS}.xml_text, {HTTP_CONSTANTS}.plain_text>>
|
content_type_supported := <<{HTTP_CONSTANTS}.json_app, {HTTP_CONSTANTS}.xml_text, {HTTP_CONSTANTS}.plain_text>>
|
||||||
l_format_id := ctx.request_format_id ("format", content_type_supported)
|
l_format_id := ctx.request_format_id ("format", content_type_supported)
|
||||||
if ctx.authenticated then
|
if authenticated (ctx) then
|
||||||
l_full := attached ctx.query_parameter ("details") as v and then v.is_case_insensitive_equal ("true")
|
l_full := attached ctx.query_parameter ("details") as v and then v.is_case_insensitive_equal ("true")
|
||||||
if attached ctx.authenticated_identifier as log then
|
if attached authenticated_identifier (ctx) as log then
|
||||||
l_login := log.as_string_8
|
l_login := log.as_string_8
|
||||||
|
|
||||||
create h.make
|
create h.make
|
||||||
|
|||||||
@@ -65,12 +65,12 @@ feature -- Execution
|
|||||||
(create {DEVELOPER_EXCEPTION}).raise
|
(create {DEVELOPER_EXCEPTION}).raise
|
||||||
elseif l_op.starts_with ("env") then
|
elseif l_op.starts_with ("env") then
|
||||||
s.append_string ("%N%NAll variables:")
|
s.append_string ("%N%NAll variables:")
|
||||||
s.append (wgi_value_iteration_to_string (req.parameters, False))
|
s.append (wgi_value_iteration_to_string (req.items, False))
|
||||||
s.append_string ("<br/>script_url(%"" + req.path_info + "%")=" + ctx.script_url (req.path_info) + "%N")
|
s.append_string ("<br/>script_url(%"" + req.path_info + "%")=" + ctx.script_url (req.path_info) + "%N")
|
||||||
-- if attached ctx.http_authorization_login_password as t then
|
-- if attached ctx.http_authorization_login_password as t then
|
||||||
-- s.append_string ("Check login=" + t.login + "<br/>%N")
|
-- s.append_string ("Check login=" + t.login + "<br/>%N")
|
||||||
-- end
|
-- end
|
||||||
if ctx.authenticated and then attached ctx.authenticated_identifier as l_login then
|
if authenticated (ctx) and then attached authenticated_identifier (ctx) as l_login then
|
||||||
s.append_string ("Authenticated: login=" + l_login.as_string_8 + "<br/>%N")
|
s.append_string ("Authenticated: login=" + l_login.as_string_8 + "<br/>%N")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -83,15 +83,15 @@ feature -- Execution
|
|||||||
l_redir_url: STRING
|
l_redir_url: STRING
|
||||||
do
|
do
|
||||||
create h.make
|
create h.make
|
||||||
-- h.put_refresh (ctx.script_url ("/doc"), 2, {HTTP_STATUS_CODE}.temp_redirect)
|
-- h.put_refresh (ctx.script_url ("/doc"), 2)
|
||||||
l_redir_url := "/doc"
|
l_redir_url := "/doc"
|
||||||
h.put_refresh (l_redir_url, 2, {HTTP_STATUS_CODE}.temp_redirect)
|
h.put_refresh (l_redir_url, 2)
|
||||||
h.put_content_type_text_html
|
h.put_content_type_text_html
|
||||||
create s.make_empty
|
create s.make_empty
|
||||||
s := "Request [" + req.path_info + "] is not available. <br/>%N";
|
s := "Request [" + req.path_info + "] is not available. <br/>%N";
|
||||||
s.append ("You are being redirected to <a href=%"" + l_redir_url + "%">/doc</a> in 2 seconds ...%N")
|
s.append ("You are being redirected to <a href=%"" + l_redir_url + "%">/doc</a> in 2 seconds ...%N")
|
||||||
h.put_content_length (s.count)
|
h.put_content_length (s.count)
|
||||||
res.set_status_code (200)
|
res.set_status_code ({HTTP_STATUS_CODE}.temp_redirect)
|
||||||
res.write_headers_string (h.string)
|
res.write_headers_string (h.string)
|
||||||
res.write_string (s)
|
res.write_string (s)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ inherit
|
|||||||
end
|
end
|
||||||
|
|
||||||
REST_REQUEST_AGENT_HANDLER [APP_REQUEST_HANDLER_CONTEXT]
|
REST_REQUEST_AGENT_HANDLER [APP_REQUEST_HANDLER_CONTEXT]
|
||||||
|
undefine
|
||||||
|
authenticated
|
||||||
|
end
|
||||||
|
|
||||||
create
|
create
|
||||||
make
|
make
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ deferred class
|
|||||||
|
|
||||||
inherit
|
inherit
|
||||||
REST_REQUEST_HANDLER [APP_REQUEST_HANDLER_CONTEXT]
|
REST_REQUEST_HANDLER [APP_REQUEST_HANDLER_CONTEXT]
|
||||||
|
redefine
|
||||||
|
authenticated
|
||||||
|
end
|
||||||
|
|
||||||
APP_REQUEST_HELPER
|
APP_REQUEST_HELPER
|
||||||
|
|
||||||
@@ -17,27 +20,43 @@ feature {NONE} -- Initialization
|
|||||||
-- Initialize various attributes
|
-- Initialize various attributes
|
||||||
do
|
do
|
||||||
end
|
end
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
wgi_value_iteration_to_string (cur: ITERATION_CURSOR [WGI_VALUE]; using_pre: BOOLEAN): STRING_8
|
wgi_value_iteration_to_string (v: ITERABLE [WGI_VALUE]; using_pre: BOOLEAN): STRING_8
|
||||||
do
|
do
|
||||||
create Result.make (100)
|
create Result.make (100)
|
||||||
if using_pre then
|
if using_pre then
|
||||||
Result.append ("<pre>")
|
Result.append ("<pre>")
|
||||||
end
|
end
|
||||||
from
|
across
|
||||||
until
|
v as cur
|
||||||
cur.after
|
|
||||||
loop
|
loop
|
||||||
Result.append_string (cur.item.name.as_string_8 + " = " + cur.item.as_string.as_string_8 + "%N")
|
Result.append_string (cur.item.name.as_string_8 + " = " + cur.item.as_string.as_string_8 + "%N")
|
||||||
cur.forth
|
|
||||||
end
|
end
|
||||||
if using_pre then
|
if using_pre then
|
||||||
Result.append ("</pre>")
|
Result.append ("</pre>")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature -- Auth
|
||||||
|
|
||||||
|
authenticated (ctx: APP_REQUEST_HANDLER_CONTEXT): BOOLEAN
|
||||||
|
-- Is authenticated?
|
||||||
|
do
|
||||||
|
--| To redefine if needed
|
||||||
|
if attached ctx.request.http_authorization as l_http_authorization then
|
||||||
|
Result := True
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
authenticated_identifier (ctx: APP_REQUEST_HANDLER_CONTEXT): detachable READABLE_STRING_32
|
||||||
|
do
|
||||||
|
if attached ctx.request.http_authorization as l_http_authorization then
|
||||||
|
Result := "foo" -- Implement it as you want
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
feature -- Helpers
|
feature -- Helpers
|
||||||
|
|
||||||
format_id (s: detachable STRING): INTEGER
|
format_id (s: detachable STRING): INTEGER
|
||||||
|
|||||||
@@ -9,29 +9,10 @@ class
|
|||||||
|
|
||||||
inherit
|
inherit
|
||||||
REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT
|
REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT
|
||||||
redefine
|
|
||||||
authenticated,
|
|
||||||
authenticated_identifier
|
|
||||||
end
|
|
||||||
|
|
||||||
create
|
create
|
||||||
make
|
make
|
||||||
|
|
||||||
feature -- Auth
|
|
||||||
|
|
||||||
authenticated: BOOLEAN
|
|
||||||
do
|
|
||||||
if attached request.http_authorization as l_http_auth then
|
|
||||||
Result := True
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
authenticated_identifier: detachable READABLE_STRING_32
|
|
||||||
do
|
|
||||||
if authenticated then
|
|
||||||
Result := "foo"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Format
|
feature -- Format
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,14 @@ class
|
|||||||
inherit
|
inherit
|
||||||
APP_REQUEST_HANDLER
|
APP_REQUEST_HANDLER
|
||||||
undefine
|
undefine
|
||||||
execute,
|
execute
|
||||||
pre_execute,
|
|
||||||
post_execute
|
|
||||||
end
|
end
|
||||||
|
|
||||||
REST_REQUEST_URI_TEMPLATE_ROUTING_HANDLER_I [APP_REQUEST_HANDLER, APP_REQUEST_HANDLER_CONTEXT]
|
REST_REQUEST_URI_TEMPLATE_ROUTING_HANDLER_I [APP_REQUEST_HANDLER, APP_REQUEST_HANDLER_CONTEXT]
|
||||||
|
undefine
|
||||||
|
authenticated,
|
||||||
|
pre_execute,
|
||||||
|
post_execute
|
||||||
redefine
|
redefine
|
||||||
router
|
router
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,31 +14,28 @@ feature -- Helper
|
|||||||
|
|
||||||
execute_content_type_not_allowed (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; a_content_types: detachable ARRAY [STRING]; a_uri_formats: detachable ARRAY [STRING])
|
execute_content_type_not_allowed (req: WGI_REQUEST; res: WGI_RESPONSE_BUFFER; a_content_types: detachable ARRAY [STRING]; a_uri_formats: detachable ARRAY [STRING])
|
||||||
local
|
local
|
||||||
s, uri_s: detachable STRING
|
accept_s, uri_s: detachable STRING
|
||||||
i, n: INTEGER
|
i, n: INTEGER
|
||||||
h: EWF_HEADER
|
|
||||||
do
|
do
|
||||||
create h.make
|
|
||||||
h.put_status ({HTTP_STATUS_CODE}.unsupported_media_type)
|
|
||||||
h.put_content_type_text_plain
|
|
||||||
|
|
||||||
if a_content_types /= Void then
|
if a_content_types /= Void then
|
||||||
create s.make (10)
|
create accept_s.make (10)
|
||||||
from
|
from
|
||||||
i := a_content_types.lower
|
i := a_content_types.lower
|
||||||
n := a_content_types.upper
|
n := a_content_types.upper
|
||||||
until
|
until
|
||||||
i > n
|
i > n
|
||||||
loop
|
loop
|
||||||
s.append_string (a_content_types[i])
|
accept_s.append_string (a_content_types[i])
|
||||||
if i < n then
|
if i < n then
|
||||||
s.append_character (',')
|
accept_s.append_character (',')
|
||||||
s.append_character (' ')
|
accept_s.append_character (' ')
|
||||||
end
|
end
|
||||||
i := i + 1
|
i := i + 1
|
||||||
end
|
end
|
||||||
h.put_header_key_value ("Accept", s)
|
else
|
||||||
|
accept_s := "*/*"
|
||||||
end
|
end
|
||||||
|
|
||||||
if a_uri_formats /= Void then
|
if a_uri_formats /= Void then
|
||||||
create uri_s.make (10)
|
create uri_s.make (10)
|
||||||
from
|
from
|
||||||
@@ -56,9 +53,9 @@ feature -- Helper
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
res.set_status_code ({HTTP_STATUS_CODE}.unsupported_media_type)
|
res.set_status_code ({HTTP_STATUS_CODE}.unsupported_media_type)
|
||||||
res.write_headers_string (h.string)
|
res.write_header ({HTTP_STATUS_CODE}.unsupported_media_type, << ["Content-Type", "text/plain"], ["Accept", accept_s]>>)
|
||||||
if s /= Void then
|
if accept_s /= Void then
|
||||||
res.write_string ("Unsupported request content-type, Accept: " + s + "%N")
|
res.write_string ("Unsupported request content-type, Accept: " + accept_s + "%N")
|
||||||
end
|
end
|
||||||
if uri_s /= Void then
|
if uri_s /= Void then
|
||||||
res.write_string ("Unsupported request format from the URI: " + uri_s + "%N")
|
res.write_string ("Unsupported request format from the URI: " + uri_s + "%N")
|
||||||
|
|||||||
Reference in New Issue
Block a user