Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -35,6 +35,10 @@ For more information please have a look at the related wiki:
|
||||
For download, check
|
||||
* https://github.com/EiffelWebFramework/EWF/downloads
|
||||
|
||||
Tasks and issues are managed with github issue system
|
||||
* See https://github.com/EiffelWebFramework/EWF/issues
|
||||
* And visual dashboard: https://waffle.io/eiffelwebframework/ewf
|
||||
|
||||
## Requirements
|
||||
* Compiling from EiffelStudio 7.2 to 13.11 and more recent version of the compiler.
|
||||
* Developped using EiffelStudio 13.11 (on Windows, Linux)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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="nino" uuid="32C1D67D-33DE-4F1E-864B-D45388F2E3E6" library_target="nino">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="nino" uuid="32C1D67D-33DE-4F1E-864B-D45388F2E3E6" library_target="nino">
|
||||
<target name="nino">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -8,7 +8,7 @@
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" is_attached_by_default="true" void_safety="all">
|
||||
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="json" uuid="4E21C3BD-7951-4C6E-A673-431E762D7414" library_target="json">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="json" uuid="4E21C3BD-7951-4C6E-A673-431E762D7414" library_target="json">
|
||||
<target name="json">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
|
||||
@@ -61,99 +61,29 @@ feature -- Access
|
||||
item: STRING
|
||||
-- Contents with escaped entities if any
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
unescaped_string_8: STRING_8
|
||||
-- Unescaped string from `item'
|
||||
-- Unescaped string from `item'.
|
||||
--| note: valid only if `item' does not encode any unicode character.
|
||||
local
|
||||
s: like item
|
||||
i, n: INTEGER
|
||||
c: CHARACTER
|
||||
do
|
||||
s := item
|
||||
n := s.count
|
||||
create Result.make (n)
|
||||
from i := 1 until i > n loop
|
||||
c := s[i]
|
||||
if c = '\' then
|
||||
if i < n then
|
||||
inspect s[i+1]
|
||||
when '\' then
|
||||
Result.append_character ('\')
|
||||
i := i + 2
|
||||
when '%"' then
|
||||
Result.append_character ('%"')
|
||||
i := i + 2
|
||||
when 'n' then
|
||||
Result.append_character ('%N')
|
||||
i := i + 2
|
||||
when 'r' then
|
||||
Result.append_character ('%R')
|
||||
i := i + 2
|
||||
when 'u' then
|
||||
--| Leave Unicode \uXXXX unescaped
|
||||
Result.append_character ('\')
|
||||
i := i + 1
|
||||
else
|
||||
Result.append_character ('\')
|
||||
i := i + 1
|
||||
end
|
||||
else
|
||||
Result.append_character ('\')
|
||||
i := i + 1
|
||||
end
|
||||
else
|
||||
Result.append_character (c)
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
create Result.make (s.count)
|
||||
unescape_to_string_8 (Result)
|
||||
end
|
||||
|
||||
unescaped_string_32: STRING_32
|
||||
-- Unescaped string 32 from `item'
|
||||
--| some encoders uses UTF-8 , and not the recommended pure json encoding
|
||||
--| thus, let's support the UTF-8 encoding during decoding.
|
||||
local
|
||||
s: like item
|
||||
i, n: INTEGER
|
||||
c: CHARACTER
|
||||
hex: STRING
|
||||
s: READABLE_STRING_8
|
||||
do
|
||||
s := item
|
||||
n := s.count
|
||||
create Result.make (n)
|
||||
from i := 1 until i > n loop
|
||||
c := s[i]
|
||||
if c = '\' then
|
||||
if i < n then
|
||||
inspect s[i+1]
|
||||
when '\' then
|
||||
Result.append_character ('\')
|
||||
i := i + 2
|
||||
when '%"' then
|
||||
Result.append_character ('%"')
|
||||
i := i + 2
|
||||
when 'n' then
|
||||
Result.append_character ('%N')
|
||||
i := i + 2
|
||||
when 'r' then
|
||||
Result.append_character ('%R')
|
||||
i := i + 2
|
||||
when 'u' then
|
||||
hex := s.substring (i+2, i+2+4 - 1)
|
||||
if hex.count = 4 then
|
||||
Result.append_code (hexadecimal_to_natural_32 (hex))
|
||||
end
|
||||
i := i + 2 + 4
|
||||
else
|
||||
Result.append_character ('\')
|
||||
i := i + 1
|
||||
end
|
||||
else
|
||||
Result.append_character ('\')
|
||||
i := i + 1
|
||||
end
|
||||
else
|
||||
Result.append_character (c.to_character_32)
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
create Result.make (s.count)
|
||||
unescape_to_string_32 (Result)
|
||||
end
|
||||
|
||||
representation: STRING
|
||||
@@ -165,6 +95,156 @@ feature -- Access
|
||||
Result.append_character ('%"')
|
||||
end
|
||||
|
||||
unescape_to_string_8 (a_output: STRING_8)
|
||||
-- Unescape string `item' into `a_output'.
|
||||
--| note: valid only if `item' does not encode any unicode character.
|
||||
local
|
||||
s: like item
|
||||
i, n: INTEGER
|
||||
c: CHARACTER
|
||||
do
|
||||
s := item
|
||||
n := s.count
|
||||
from i := 1 until i > n loop
|
||||
c := s[i]
|
||||
if c = '\' then
|
||||
if i < n then
|
||||
inspect s[i+1]
|
||||
when '\' then
|
||||
a_output.append_character ('\')
|
||||
i := i + 2
|
||||
when '%"' then
|
||||
a_output.append_character ('%"')
|
||||
i := i + 2
|
||||
when 'b' then
|
||||
a_output.append_character ('%B')
|
||||
i := i + 2
|
||||
when 'f' then
|
||||
a_output.append_character ('%F')
|
||||
i := i + 2
|
||||
when 'n' then
|
||||
a_output.append_character ('%N')
|
||||
i := i + 2
|
||||
when 'r' then
|
||||
a_output.append_character ('%R')
|
||||
i := i + 2
|
||||
when 't' then
|
||||
a_output.append_character ('%T')
|
||||
i := i + 2
|
||||
when 'u' then
|
||||
--| Leave Unicode \uXXXX unescaped
|
||||
a_output.append_character ('\')
|
||||
i := i + 1
|
||||
else
|
||||
a_output.append_character ('\')
|
||||
i := i + 1
|
||||
end
|
||||
else
|
||||
a_output.append_character ('\')
|
||||
i := i + 1
|
||||
end
|
||||
else
|
||||
a_output.append_character (c)
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
unescape_to_string_32 (a_output: STRING_32)
|
||||
-- Unescape string `item' into `a_output' string 32.
|
||||
--| some encoders uses UTF-8 , and not the recommended pure json encoding
|
||||
--| thus, let's support the UTF-8 encoding during decoding.
|
||||
local
|
||||
s: READABLE_STRING_8
|
||||
i, n: INTEGER
|
||||
c: NATURAL_32
|
||||
ch: CHARACTER_8
|
||||
hex: READABLE_STRING_8
|
||||
do
|
||||
s := item
|
||||
n := s.count
|
||||
from i := 1 until i > n loop
|
||||
ch := s.item (i)
|
||||
if ch = '\' then
|
||||
if i < n then
|
||||
inspect s[i+1]
|
||||
when '\' then
|
||||
a_output.append_character ('\')
|
||||
i := i + 2
|
||||
when '%"' then
|
||||
a_output.append_character ('%"')
|
||||
i := i + 2
|
||||
when 'b' then
|
||||
a_output.append_character ('%B')
|
||||
i := i + 2
|
||||
when 'f' then
|
||||
a_output.append_character ('%F')
|
||||
i := i + 2
|
||||
when 'n' then
|
||||
a_output.append_character ('%N')
|
||||
i := i + 2
|
||||
when 'r' then
|
||||
a_output.append_character ('%R')
|
||||
i := i + 2
|
||||
when 't' then
|
||||
a_output.append_character ('%T')
|
||||
i := i + 2
|
||||
when 'u' then
|
||||
hex := s.substring (i + 2, i + 5) -- i+2 , i+2+4-1
|
||||
if hex.count = 4 then
|
||||
a_output.append_code (hexadecimal_to_natural_32 (hex))
|
||||
end
|
||||
i := i + 6 -- i +2 +4
|
||||
else
|
||||
a_output.append_character ('\')
|
||||
i := i + 1
|
||||
end
|
||||
else
|
||||
a_output.append_character ('\')
|
||||
i := i + 1
|
||||
end
|
||||
else
|
||||
c := ch.natural_32_code
|
||||
if c <= 0x7F then
|
||||
-- 0xxxxxxx
|
||||
check ch = c.to_character_32 end
|
||||
a_output.append_character (ch)
|
||||
elseif c <= 0xDF then
|
||||
-- 110xxxxx 10xxxxxx
|
||||
i := i + 1
|
||||
if i <= n then
|
||||
a_output.append_code (
|
||||
((c & 0x1F) |<< 6) |
|
||||
(s.code (i) & 0x3F)
|
||||
)
|
||||
end
|
||||
elseif c <= 0xEF then
|
||||
-- 1110xxxx 10xxxxxx 10xxxxxx
|
||||
i := i + 2
|
||||
if i <= n then
|
||||
a_output.append_code (
|
||||
((c & 0xF) |<< 12) |
|
||||
((s.code (i - 1) & 0x3F) |<< 6) |
|
||||
(s.code (i) & 0x3F)
|
||||
)
|
||||
end
|
||||
elseif c <= 0xF7 then
|
||||
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
i := i + 3
|
||||
if i <= n then
|
||||
a_output.append_code (
|
||||
((c & 0x7) |<< 18) |
|
||||
((s.code (i - 2) & 0x3F) |<< 12) |
|
||||
((s.code (i - 1) & 0x3F) |<< 6) |
|
||||
(s.code (i) & 0x3F)
|
||||
)
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Visitor pattern
|
||||
|
||||
accept (a_visitor: JSON_VISITOR)
|
||||
@@ -213,8 +293,18 @@ feature {NONE} -- Implementation
|
||||
|
||||
is_hexadecimal (s: READABLE_STRING_8): BOOLEAN
|
||||
-- Is `s' an hexadecimal value?
|
||||
local
|
||||
i: INTEGER
|
||||
do
|
||||
Result := across s as scur all scur.item.is_hexa_digit end
|
||||
from
|
||||
Result := True
|
||||
i := 1
|
||||
until
|
||||
i > s.count or not Result
|
||||
loop
|
||||
Result := s[i].is_hexa_digit
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
hexadecimal_to_natural_32 (s: READABLE_STRING_8): NATURAL_32
|
||||
@@ -264,8 +354,11 @@ feature {NONE} -- Implementation
|
||||
inspect c
|
||||
when '%"' then Result.append_string ("\%"")
|
||||
when '\' then Result.append_string ("\\")
|
||||
when '%R' then Result.append_string ("\r")
|
||||
when '%B' then Result.append_string ("\b")
|
||||
when '%F' then Result.append_string ("\f")
|
||||
when '%N' then Result.append_string ("\n")
|
||||
when '%R' then Result.append_string ("\r")
|
||||
when '%T' then Result.append_string ("\t")
|
||||
else
|
||||
Result.extend (c)
|
||||
end
|
||||
@@ -292,8 +385,11 @@ feature {NONE} -- Implementation
|
||||
inspect c
|
||||
when '%"' then Result.append_string ("\%"")
|
||||
when '\' then Result.append_string ("\\")
|
||||
when '%R' then Result.append_string ("\r")
|
||||
when '%B' then Result.append_string ("\b")
|
||||
when '%F' then Result.append_string ("\f")
|
||||
when '%N' then Result.append_string ("\n")
|
||||
when '%R' then Result.append_string ("\r")
|
||||
when '%T' then Result.append_string ("\t")
|
||||
else
|
||||
Result.extend (c)
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
note
|
||||
note
|
||||
description: "[
|
||||
Eiffel tests that can be executed by testing tool.
|
||||
]"
|
||||
@@ -62,6 +62,27 @@ feature -- Tests Pass
|
||||
end
|
||||
end
|
||||
|
||||
test_json_utf_8_pass1
|
||||
local
|
||||
parse_json: like new_json_parser
|
||||
utf: UTF_CONVERTER
|
||||
s: READABLE_STRING_32
|
||||
do
|
||||
s := {STRING_32} "{ %"nihaoma%": %"你好吗\t?%" }"
|
||||
|
||||
parse_json := new_json_parser (utf.string_32_to_utf_8_string_8 (s))
|
||||
json_value := parse_json.parse_json
|
||||
assert ("utf8.pass1.json", parse_json.is_parsed = True)
|
||||
if
|
||||
attached {JSON_OBJECT} json_value as jo and then
|
||||
attached {JSON_STRING} jo.item ("nihaoma") as js
|
||||
then
|
||||
assert ("utf8.nihaoma", js.unescaped_string_32.same_string ({STRING_32} "你好吗%T?"))
|
||||
else
|
||||
assert ("utf8.nihaoma", False)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Tests Failures
|
||||
test_json_fail1
|
||||
--
|
||||
|
||||
@@ -14,7 +14,8 @@ The framework also provides a router component to help dispatching the incoming
|
||||
|
||||
A service can be a web api, a web interface, … what ever run on top of HTTP.
|
||||
|
||||
<a name="wiki-service"/>
|
||||
<a name="wiki-service"></a>
|
||||
<a name="service"></a>
|
||||
# Service
|
||||
> see interface: **WSF_SERVICE**
|
||||
|
||||
@@ -28,7 +29,8 @@ For convenience, the framework provides richer service interface that handles th
|
||||
|
||||
> [Learn more about service](Documentation__Service)
|
||||
|
||||
<a name="wiki-request"/><a name="wiki-response"/><a name="wiki-request-and-response"/>
|
||||
<a name="wiki-request"></a><a name="wiki-response"></a><a name="wiki-request-and-response"></a>
|
||||
<a name="request"></a><a name="response"></a><a name="request-and-response"></a>
|
||||
# Request and Response
|
||||
> see interface: **WSF_REQUEST** and **WSF_RESPONSE**
|
||||
|
||||
@@ -50,7 +52,8 @@ The **WSF_RESPONSE** represents the communication toward the client, a service n
|
||||
|
||||
> [Learn more about request](Documentation__Request) and [about response](Documentation__Response)
|
||||
|
||||
<a name="wiki-connector"/>
|
||||
<a name="wiki-connector"></a>
|
||||
<a name="connector"></a>
|
||||
# Connectors:
|
||||
> see **WGI_CONNECTOR**
|
||||
|
||||
@@ -65,7 +68,8 @@ It is fairly easy to add new connector, it just has to follow the EWSGI interfac
|
||||
|
||||
> [Learn more about connector](Documentation__Connector)
|
||||
|
||||
<a name="wiki-router"/>
|
||||
<a name="wiki-router"></a>
|
||||
<a name="router"></a>
|
||||
# Router or Request Dispatcher:
|
||||
> Routes HTTP requests to the proper execution code
|
||||
|
||||
@@ -165,10 +169,12 @@ examples
|
||||
## EWF application generators
|
||||
|
||||
|
||||
<a name="wiki-EWSGI"/>
|
||||
<a name="wiki-EWSGI"></a>
|
||||
<a name="EWSGI"></a>
|
||||
# EWSGI Specification
|
||||
|
||||
<a name="wiki-libraries"/>
|
||||
<a name="wiki-libraries"></a>
|
||||
<a name="libraries"></a>
|
||||
# Libraries
|
||||
|
||||
External libraries are included, such as Cypress OAuth (Security), HTML parsing library, Template Engine Smarty.
|
||||
|
||||
@@ -1 +1,17 @@
|
||||
See WSF_REQUEST
|
||||
See WSF_REQUEST
|
||||
|
||||
## About parameters
|
||||
Note that by default there is a smart computation for the query/post/... parameters:
|
||||
for instance
|
||||
- `q=a&q=b` : will create a **WSF_MULTIPLE_STRING** parameter with name **q** and value `[a,b]`
|
||||
- `tab[a]=ewf&tab[b]=demo` : will create a **WSF_TABLE** parameter with name **tab** and value `{ "a": "ewf", "b": "demo"}`
|
||||
- `tab[]=ewf&tab[]=demo` : will create a **WSF_TABLE** parameter with name **tab** and value `{ "1": "ewf", "2": "demo"}`
|
||||
- `tab[foo]=foo&tab[foo]=bar` : will create a **WSF_TABLE** parameter with name **tab** and value `{ "foo": "bar"}` **WARNING: only the last `tab[foo]` is kept**.
|
||||
|
||||
Those rules are applied to query, post, path, .... parameters.
|
||||
|
||||
## How to get the input data (i.e entity-body) ?
|
||||
See `{WSF_REQUEST}.read_input_data_into (buf: STRING)`
|
||||
|
||||
## How to get the raw header data (i.e the http header text) ?
|
||||
See `{WSF_REQUEST}.raw_header_data: detachable READABLE_STRING_32`
|
||||
|
||||
2
examples/desktop_app/README.md
Normal file
2
examples/desktop_app/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
This example demonstrates the use of embedded Vision2 web browser component, and embedded EWF server (using nino).
|
||||
|
||||
28
examples/desktop_app/desktop_app.ecf
Normal file
28
examples/desktop_app/desktop_app.ecf
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="desktop_app" uuid="E015841A-D456-46E1-8A18-E0CEB9E69CD5">
|
||||
<description>Vision2+web browser widget+embedded web service</description>
|
||||
<target name="desktop_app">
|
||||
<description>This example demonstrates how to build a vision2 desktop application that embed a web browser accessing the service of an embedded web service.</description>
|
||||
<root class="DESKTOP_APP" feature="make_and_launch"/>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<precompile name="vision2-pre" location="$ISE_PRECOMP\vision2-mt-safe.ecf"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi" location="..\..\library\server\ewsgi\ewsgi-safe.ecf"/>
|
||||
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
|
||||
<library name="vision2" location="$ISE_LIBRARY\library\vision2\vision2-safe.ecf"/>
|
||||
<library name="web_browser" location="$ISE_LIBRARY\library\web_browser\web_browser-safe.ecf" readonly="false"/>
|
||||
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
|
||||
<library name="wsf_nino" location="..\..\library\server\wsf\connector\nino-safe.ecf"/>
|
||||
<library name="wsf_nino_connector" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf"/>
|
||||
<cluster name="src" location=".\src" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</target>
|
||||
</system>
|
||||
1
examples/desktop_app/files/index.html
Normal file
1
examples/desktop_app/files/index.html
Normal file
@@ -0,0 +1 @@
|
||||
Test
|
||||
32
examples/desktop_app/home.html
Normal file
32
examples/desktop_app/home.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
function loadXMLDoc()
|
||||
{
|
||||
var xmlhttp;
|
||||
if (window.XMLHttpRequest)
|
||||
{// code for IE7+, Firefox, Chrome, Opera, Safari
|
||||
xmlhttp=new XMLHttpRequest();
|
||||
}
|
||||
else
|
||||
{// code for IE6, IE5
|
||||
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
xmlhttp.onreadystatechange=function()
|
||||
{
|
||||
if (xmlhttp.readyState==4 && xmlhttp.status==200)
|
||||
{
|
||||
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
|
||||
}
|
||||
}
|
||||
xmlhttp.open("GET","http://localhost:52367/test/ajax.txt",true);
|
||||
xmlhttp.send();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>This is a local file test with js</h1><li><a href="http://localhost:52367/">back to home</a></li><div id="myDiv"><h2>Let AJAX change this text</h2>
|
||||
<button type="button" onclick="loadXMLDoc()">Change Content</button>
|
||||
</div>
|
||||
</body></html>
|
||||
230
examples/desktop_app/src/app_embedded_web_service.e
Normal file
230
examples/desktop_app/src/app_embedded_web_service.e
Normal file
@@ -0,0 +1,230 @@
|
||||
note
|
||||
description: "Summary description for {APP_EMBEDDED_WEB_SERVICE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
APP_EMBEDDED_WEB_SERVICE
|
||||
|
||||
inherit
|
||||
EMBEDDED_WEB_SERVICE
|
||||
redefine
|
||||
make
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
Precursor
|
||||
create request_exit_operation_actions
|
||||
local_connection_restriction_enabled := True
|
||||
end
|
||||
|
||||
feature -- Execution
|
||||
|
||||
request_exit_operation_actions: ACTION_SEQUENCE [TUPLE]
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the request
|
||||
-- See `req.input' for input stream
|
||||
-- `req.meta_variables' for the CGI meta variable
|
||||
-- and `res' for output buffer
|
||||
local
|
||||
router: WSF_ROUTER
|
||||
sess: detachable WSF_ROUTER_SESSION
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
b: STRING
|
||||
fs: WSF_FILE_SYSTEM_HANDLER
|
||||
do
|
||||
create router.make (3)
|
||||
router.handle ("/test/{var}", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_test))
|
||||
router.handle ("/env", create {WSF_URI_AGENT_HANDLER}.make (agent handle_env))
|
||||
router.handle ("/exit", create {WSF_URI_TEMPLATE_AGENT_HANDLER}.make (agent handle_exit))
|
||||
create fs.make_with_path ((create {EXECUTION_ENVIRONMENT}).current_working_path.extended ("files"))
|
||||
router.handle ("/files", fs)
|
||||
create sess
|
||||
router.dispatch (req, res, sess)
|
||||
if not sess.dispatched then
|
||||
create m.make
|
||||
create b.make_from_string ("<h1>Hello Eiffel desktop user</h1>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/test/start") + "%">test</a></li>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/env") + "%">env</a></li>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/files") + "%">files</a></li>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/exit") + "%">exit</a></li>")
|
||||
m.set_body (b)
|
||||
res.send (m)
|
||||
end
|
||||
end
|
||||
|
||||
handle_test (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
b: STRING
|
||||
l_name: READABLE_STRING_32
|
||||
do
|
||||
if attached {WSF_STRING} req.item ("var") as p_name then
|
||||
l_name := p_name.value
|
||||
else
|
||||
l_name := {STRING_32} "Embedded web service and web_browser in vision2 application"
|
||||
end
|
||||
create m.make
|
||||
create b.make_from_string ("<h1>This is a test about "+ m.html_encoded_string (l_name) +"</h1>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/") + "%">back to home</a></li>")
|
||||
if l_name.is_case_insensitive_equal_general ("start") then
|
||||
b.append ("<li><a href=%"" + req.script_url ("/test/js") + "%">test javascript+ajax</a></li>")
|
||||
elseif l_name.is_case_insensitive_equal_general ("js") then
|
||||
b.append ("[
|
||||
<div id="myDiv"><h2>Let AJAX change this text</h2>
|
||||
<button type="button" onclick="loadXMLDoc()">Change Content</button>
|
||||
</div>
|
||||
]")
|
||||
m.add_javascript_content ("[
|
||||
function loadXMLDoc()
|
||||
{
|
||||
var xmlhttp;
|
||||
if (window.XMLHttpRequest)
|
||||
{// code for IE7+, Firefox, Chrome, Opera, Safari
|
||||
xmlhttp=new XMLHttpRequest();
|
||||
}
|
||||
else
|
||||
{// code for IE6, IE5
|
||||
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
xmlhttp.onreadystatechange=function()
|
||||
{
|
||||
if (xmlhttp.readyState==4 && xmlhttp.status==200)
|
||||
{
|
||||
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
|
||||
}
|
||||
}
|
||||
xmlhttp.open("GET","/test/ajax.txt",true);
|
||||
xmlhttp.send();
|
||||
}
|
||||
]")
|
||||
elseif l_name.is_case_insensitive_equal_general ("ajax.txt") then
|
||||
b := "This is AJAX response ... from " + req.absolute_script_url ("")
|
||||
end
|
||||
m.set_body (b)
|
||||
res.send (m)
|
||||
end
|
||||
|
||||
handle_env (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
s: STRING_8
|
||||
p: WSF_PAGE_RESPONSE
|
||||
v: STRING_8
|
||||
do
|
||||
create s.make (2048)
|
||||
s.append ("**DEBUG**%N")
|
||||
req.set_raw_input_data_recorded (True)
|
||||
|
||||
append_iterable_to ("Meta variables:", req.meta_variables, s)
|
||||
s.append_character ('%N')
|
||||
|
||||
append_iterable_to ("Path parameters", req.path_parameters, s)
|
||||
s.append_character ('%N')
|
||||
|
||||
append_iterable_to ("Query parameters", req.query_parameters, s)
|
||||
s.append_character ('%N')
|
||||
|
||||
append_iterable_to ("Form parameters", req.form_parameters, s)
|
||||
s.append_character ('%N')
|
||||
|
||||
if attached req.content_type as l_type then
|
||||
s.append ("Content: type=" + l_type.debug_output)
|
||||
s.append (" length=")
|
||||
s.append_natural_64 (req.content_length_value)
|
||||
s.append_character ('%N')
|
||||
create v.make (req.content_length_value.to_integer_32)
|
||||
req.read_input_data_into (v)
|
||||
across
|
||||
v.split ('%N') as v_cursor
|
||||
loop
|
||||
s.append (" |")
|
||||
s.append (v_cursor.item)
|
||||
s.append_character ('%N')
|
||||
end
|
||||
end
|
||||
|
||||
create p.make_with_body (s)
|
||||
p.header.put_content_type_text_plain
|
||||
res.send (p)
|
||||
end
|
||||
|
||||
handle_exit (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
m: WSF_HTML_PAGE_RESPONSE
|
||||
b: STRING
|
||||
do
|
||||
create m.make
|
||||
create b.make_from_string ("<h1>Embedded server is about to shutdown</h1>")
|
||||
b.append ("<li><a href=%"" + req.script_url ("/") + "%">back to home</a></li>")
|
||||
m.set_body (b)
|
||||
res.send (m)
|
||||
if attached {WGI_NINO_CONNECTOR} req.wgi_connector as nino then
|
||||
nino.server.shutdown_server
|
||||
end
|
||||
request_exit_operation_actions.call (Void)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
append_iterable_to (a_title: READABLE_STRING_8; it: detachable ITERABLE [WSF_VALUE]; s: STRING_8)
|
||||
local
|
||||
n: INTEGER
|
||||
t: READABLE_STRING_8
|
||||
v: READABLE_STRING_8
|
||||
do
|
||||
s.append (a_title)
|
||||
s.append_character (':')
|
||||
if it /= Void then
|
||||
across it as c loop
|
||||
n := n + 1
|
||||
end
|
||||
if n = 0 then
|
||||
s.append (" empty")
|
||||
s.append_character ('%N')
|
||||
else
|
||||
s.append_character ('%N')
|
||||
across
|
||||
it as c
|
||||
loop
|
||||
s.append (" - ")
|
||||
s.append (c.item.url_encoded_name)
|
||||
t := c.item.generating_type
|
||||
if t.same_string ("WSF_STRING") then
|
||||
else
|
||||
s.append_character (' ')
|
||||
s.append_character ('{')
|
||||
s.append (t)
|
||||
s.append_character ('}')
|
||||
end
|
||||
s.append_character ('=')
|
||||
v := c.item.string_representation.as_string_8
|
||||
if v.has ('%N') then
|
||||
s.append_character ('%N')
|
||||
across
|
||||
v.split ('%N') as v_cursor
|
||||
loop
|
||||
s.append (" |")
|
||||
s.append (v_cursor.item)
|
||||
s.append_character ('%N')
|
||||
end
|
||||
else
|
||||
s.append (v)
|
||||
s.append_character ('%N')
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
s.append (" none")
|
||||
s.append_character ('%N')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
71
examples/desktop_app/src/desktop_app.e
Normal file
71
examples/desktop_app/src/desktop_app.e
Normal file
@@ -0,0 +1,71 @@
|
||||
note
|
||||
description: "Objects that represent the Vision2 application.%
|
||||
%The original version of this class has been generated by EiffelBuild."
|
||||
generator: "EiffelBuild"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date: 2012-09-29 01:29:13 +0200 (sam., 29 sept. 2012) $"
|
||||
revision: "$Revision: 89488 $"
|
||||
|
||||
|
||||
class
|
||||
DESKTOP_APP
|
||||
|
||||
inherit
|
||||
EV_APPLICATION
|
||||
|
||||
create
|
||||
make_and_launch
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_and_launch
|
||||
-- Create `Current', build and display `main_window',
|
||||
-- then launch the application.
|
||||
local
|
||||
l_win: like main_window
|
||||
l_embeded_services: APP_EMBEDDED_WEB_SERVICE
|
||||
do
|
||||
default_create
|
||||
create l_win.make
|
||||
main_window := l_win
|
||||
l_win.show
|
||||
create l_embeded_services.make
|
||||
l_embeded_services.set_port_number (0) -- Use first available port number
|
||||
|
||||
l_embeded_services.on_launched_actions.force (agent on_web_service_launched (l_win))
|
||||
l_embeded_services.request_exit_operation_actions.force (agent on_quit)
|
||||
l_embeded_services.launch
|
||||
launch
|
||||
end
|
||||
|
||||
on_quit
|
||||
do
|
||||
if attached main_window as win then
|
||||
win.destroy_and_exit_if_last
|
||||
end
|
||||
end
|
||||
|
||||
on_web_service_launched (a_win: attached like main_window)
|
||||
do
|
||||
add_idle_action_kamikaze (agent a_win.open_link)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
main_window: detachable MAIN_WINDOW
|
||||
-- Main window of `Current'
|
||||
|
||||
;note
|
||||
copyright: "Copyright (c) 1984-2009, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
356 Storke Road, Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
202
examples/desktop_app/src/main_window.e
Normal file
202
examples/desktop_app/src/main_window.e
Normal file
@@ -0,0 +1,202 @@
|
||||
note
|
||||
description: "Objects that represent an EV_TITLED_WINDOW.%
|
||||
%The original version of this class was generated by EiffelBuild."
|
||||
generator: "EiffelBuild"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date: 2010-08-17 10:49:12 +0200 (mar., 17 août 2010) $"
|
||||
revision: "$Revision: 84189 $"
|
||||
|
||||
class
|
||||
MAIN_WINDOW
|
||||
|
||||
inherit
|
||||
EV_TITLED_WINDOW
|
||||
redefine
|
||||
create_interface_objects, initialize, is_in_default_state
|
||||
end
|
||||
|
||||
SHARED_EMBEDED_WEB_SERVICE_INFORMATION
|
||||
undefine
|
||||
default_create, copy
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Creation method
|
||||
do
|
||||
default_create
|
||||
end
|
||||
|
||||
initialize
|
||||
-- Initialize `Current'.
|
||||
do
|
||||
Precursor {EV_TITLED_WINDOW}
|
||||
|
||||
set_title ("Desktop Application (demo embedded EWF+browser)")
|
||||
|
||||
-- Connect events.
|
||||
-- Close the application when an interface close
|
||||
-- request is received on `Current'. i.e. the cross is clicked.
|
||||
close_request_actions.extend (agent destroy_and_exit_if_last)
|
||||
|
||||
-- Call `user_initialization'.
|
||||
user_initialization
|
||||
end
|
||||
|
||||
create_interface_objects
|
||||
-- Create objects
|
||||
do
|
||||
create home_button.make_with_text ("Home")
|
||||
create back_button.make_with_text ("Back")
|
||||
create forth_button.make_with_text ("Forth")
|
||||
create refresh_button.make_with_text ("Refresh")
|
||||
create stop_button.make_with_text ("Stop")
|
||||
create url_text_field.make_with_text ("http://localhost:" + port_number.out)
|
||||
create go_button.make_with_text ("Go")
|
||||
|
||||
create web_browser
|
||||
end
|
||||
|
||||
user_initialization
|
||||
-- Called by `initialize'.
|
||||
-- Any custom user initialization that
|
||||
-- could not be performed in `initialize',
|
||||
-- (due to regeneration of implementation class)
|
||||
-- can be added here.
|
||||
local
|
||||
l_browser_box: EV_VERTICAL_BOX
|
||||
l_server_box: EV_VERTICAL_BOX
|
||||
l_hor_box: EV_HORIZONTAL_BOX
|
||||
vb: EV_VERTICAL_BOX
|
||||
do
|
||||
set_size (800, 600)
|
||||
|
||||
create vb
|
||||
extend (vb)
|
||||
vb.set_border_width (3)
|
||||
vb.set_padding_width (3)
|
||||
|
||||
-- browser part
|
||||
create l_browser_box
|
||||
|
||||
create l_hor_box
|
||||
l_browser_box.extend (l_hor_box)
|
||||
l_browser_box.disable_item_expand (l_hor_box)
|
||||
|
||||
home_button.select_actions.force_extend (agent on_home_button_action)
|
||||
l_hor_box.extend (home_button)
|
||||
l_hor_box.disable_item_expand (home_button)
|
||||
|
||||
back_button.select_actions.force_extend (agent on_back_button_action)
|
||||
l_hor_box.extend (back_button)
|
||||
l_hor_box.disable_item_expand (back_button)
|
||||
|
||||
forth_button.select_actions.force_extend (agent on_forth_button_action)
|
||||
l_hor_box.extend (forth_button)
|
||||
l_hor_box.disable_item_expand (forth_button)
|
||||
|
||||
refresh_button.select_actions.force_extend (agent on_refresh_button_action)
|
||||
l_hor_box.extend (refresh_button)
|
||||
l_hor_box.disable_item_expand (refresh_button)
|
||||
|
||||
stop_button.select_actions.force_extend (agent on_stop_button_action)
|
||||
l_hor_box.extend (stop_button)
|
||||
l_hor_box.disable_item_expand (stop_button)
|
||||
|
||||
l_hor_box.extend (url_text_field)
|
||||
|
||||
go_button.select_actions.force_extend (agent on_go_button_action)
|
||||
l_hor_box.extend (go_button)
|
||||
l_hor_box.disable_item_expand (go_button)
|
||||
|
||||
l_browser_box.extend (web_browser)
|
||||
|
||||
--------------------
|
||||
vb.extend (l_browser_box)
|
||||
end
|
||||
|
||||
is_in_default_state: BOOLEAN
|
||||
do
|
||||
Result := True
|
||||
end
|
||||
|
||||
feature -- Basic operation
|
||||
|
||||
open_link
|
||||
do
|
||||
url_text_field.set_text ("http://localhost:" + port_number.out)
|
||||
on_go_button_action
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
home_button, go_button, back_button, forth_button, stop_button, refresh_button: EV_BUTTON
|
||||
-- Buttons
|
||||
|
||||
url_text_field: EV_TEXT_FIELD
|
||||
-- URL text field
|
||||
|
||||
on_go_button_action
|
||||
-- Action for `go_button'
|
||||
local
|
||||
l_uri: STRING_32
|
||||
do
|
||||
l_uri := url_text_field.text
|
||||
if l_uri /= Void and then not l_uri.is_empty then
|
||||
web_browser.load_uri (l_uri)
|
||||
else
|
||||
on_home_button_action
|
||||
end
|
||||
end
|
||||
|
||||
on_home_button_action
|
||||
-- Action for `home_button'
|
||||
do
|
||||
web_browser.load_uri ("http://localhost:" + port_number.out)
|
||||
end
|
||||
|
||||
on_back_button_action
|
||||
-- Action for `back_button'
|
||||
do
|
||||
web_browser.back
|
||||
end
|
||||
|
||||
on_forth_button_action
|
||||
-- Action for `forth_button'
|
||||
do
|
||||
web_browser.forth
|
||||
end
|
||||
|
||||
on_refresh_button_action
|
||||
-- Action for `refresh_button'
|
||||
do
|
||||
web_browser.refresh
|
||||
end
|
||||
|
||||
on_stop_button_action
|
||||
-- Action for `stop_button'
|
||||
do
|
||||
web_browser.stop
|
||||
end
|
||||
|
||||
web_browser: EV_WEB_BROWSER
|
||||
-- Web browser widget
|
||||
|
||||
;note
|
||||
copyright: "Copyright (c) 1984-2009, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
356 Storke Road, Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
|
||||
|
||||
end
|
||||
114
examples/desktop_app/src/service/embedded_web_service.e
Normal file
114
examples/desktop_app/src/service/embedded_web_service.e
Normal file
@@ -0,0 +1,114 @@
|
||||
note
|
||||
description: "Summary description for {EMBEDDED_WEB_SERVICE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
EMBEDDED_WEB_SERVICE
|
||||
|
||||
inherit
|
||||
THREAD
|
||||
rename
|
||||
make as make_thread,
|
||||
execute as execute_thread
|
||||
end
|
||||
|
||||
WSF_SERVICE
|
||||
rename
|
||||
execute as execute_embedded
|
||||
end
|
||||
|
||||
SHARED_EMBEDED_WEB_SERVICE_INFORMATION
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make
|
||||
do
|
||||
make_thread
|
||||
create on_launched_actions
|
||||
end
|
||||
|
||||
feature {NONE} -- Execution
|
||||
|
||||
execute_embedded (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the request
|
||||
-- See `req.input' for input stream
|
||||
-- `req.meta_variables' for the CGI meta variable
|
||||
-- and `res' for output buffer
|
||||
local
|
||||
filter: WSF_AGENT_FILTER
|
||||
m: WSF_PAGE_RESPONSE
|
||||
do
|
||||
if local_connection_restriction_enabled then
|
||||
if
|
||||
attached req.remote_addr as l_remote_addr and then
|
||||
l_remote_addr.is_case_insensitive_equal_general ("127.0.0.1")
|
||||
then
|
||||
execute (req, res)
|
||||
else
|
||||
create m.make_with_body ("Only local connection is allowed")
|
||||
m.set_status_code (403) -- Forbidden
|
||||
res.send (m)
|
||||
end
|
||||
else
|
||||
execute (req, res)
|
||||
end
|
||||
end
|
||||
|
||||
execute_thread
|
||||
local
|
||||
nino: WSF_NINO_SERVICE_LAUNCHER
|
||||
opts: WSF_SERVICE_LAUNCHER_OPTIONS
|
||||
do
|
||||
create opts.default_create
|
||||
opts.set_verbose (True)
|
||||
opts.set_option ("port", port_number)
|
||||
create nino.make (Current, opts)
|
||||
nino.on_launched_actions.force (agent on_launched)
|
||||
nino.launch
|
||||
end
|
||||
|
||||
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Execute the request
|
||||
-- See `req.input' for input stream
|
||||
-- `req.meta_variables' for the CGI meta variable
|
||||
-- and `res' for output buffer
|
||||
deferred
|
||||
end
|
||||
|
||||
on_launched (conn: WGI_CONNECTOR)
|
||||
do
|
||||
if attached {WGI_NINO_CONNECTOR} conn as nino then
|
||||
set_port_number (nino.port)
|
||||
end
|
||||
on_launched_actions.call (Void)
|
||||
end
|
||||
|
||||
feature -- Control
|
||||
|
||||
wait
|
||||
-- Wait for server to be terminated.
|
||||
do
|
||||
join
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
on_launched_actions: ACTION_SEQUENCE [TUPLE]
|
||||
|
||||
feature -- Status report
|
||||
|
||||
local_connection_restriction_enabled: BOOLEAN
|
||||
-- Accept only local connection?
|
||||
--| based on 127.0.0.1 IP
|
||||
--| TO IMPROVE
|
||||
|
||||
feature -- Change
|
||||
|
||||
set_local_connection_restriction_enabled (b: BOOLEAN)
|
||||
do
|
||||
local_connection_restriction_enabled := b
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
note
|
||||
description: "Summary description for {SHARED_EMBEDED_WEB_SERVICE_INFORMATION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
SHARED_EMBEDED_WEB_SERVICE_INFORMATION
|
||||
|
||||
feature -- Access
|
||||
|
||||
port_number: INTEGER
|
||||
do
|
||||
Result := port_number_cell.item
|
||||
end
|
||||
|
||||
set_port_number (a_port: like port_number)
|
||||
do
|
||||
port_number_cell.replace (a_port)
|
||||
end
|
||||
|
||||
port_number_cell: CELL [INTEGER]
|
||||
once ("process")
|
||||
create Result.put (0)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-9-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-9-0 http://www.eiffel.com/developers/xml/configuration-1-9-0.xsd" name="client" uuid="D0059CEB-5F5C-4D21-8C71-842BD0F88468" library_target="client">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="client" uuid="D0059CEB-5F5C-4D21-8C71-842BD0F88468" library_target="client">
|
||||
<target name="client">
|
||||
<root class="RESTBUCK_CLIENT" feature="make"/>
|
||||
<file_rule>
|
||||
@@ -11,7 +11,7 @@
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="http_client" location="../../../library/network/http_client/http_client-safe.ecf" readonly="false"/>
|
||||
<library name="http_client" location="..\..\..\library\network\http_client\http_client-safe.ecf" readonly="false"/>
|
||||
<library name="json" location="..\..\..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
|
||||
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="restbucks" uuid="2773FEAA-448F-410E-BEDE-9298C4749066" library_target="restbucks">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="restbucks" uuid="2773FEAA-448F-410E-BEDE-9298C4749066" library_target="restbucks">
|
||||
<target name="restbucks_common">
|
||||
<file_rule>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option full_class_checking="false" void_safety="all">
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="connector_nino" location="..\..\library\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false">
|
||||
@@ -14,8 +16,8 @@
|
||||
</option>
|
||||
</library>
|
||||
<library name="conneg" location="..\..\library\network\protocol\content_negotiation\conneg-safe.ecf"/>
|
||||
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf" readonly="false"/>
|
||||
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf" readonly="false"/>
|
||||
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf" readonly="false"/>
|
||||
<library name="encoder" location="..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf" readonly="false"/>
|
||||
<library name="json" location="..\..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
|
||||
@@ -27,7 +29,7 @@
|
||||
</target>
|
||||
<target name="restbucks" extends="restbucks_common">
|
||||
<root class="RESTBUCKS_SERVER" feature="make"/>
|
||||
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="provisional">
|
||||
<debug name="nino" enabled="true"/>
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
@@ -39,7 +41,7 @@
|
||||
</target>
|
||||
<target name="policy_driven_restbucks" extends="restbucks_common">
|
||||
<root class="RESTBUCKS_SERVER" feature="make"/>
|
||||
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||
<option debug="true" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="provisional">
|
||||
<debug name="nino" enabled="true"/>
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-9-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-9-0 http://www.eiffel.com/developers/xml/configuration-1-9-0.xsd" name="upload_image" uuid="F2400BE8-D8EB-48EB-B4E4-5D4377062A7F" library_target="upload_image">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="upload_image" uuid="F2400BE8-D8EB-48EB-B4E4-5D4377062A7F" library_target="upload_image">
|
||||
<target name="upload_image">
|
||||
<root class="IMAGE_UPLOADER" feature="make"/>
|
||||
<file_rule>
|
||||
@@ -20,11 +20,10 @@
|
||||
</library>
|
||||
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf" readonly="false" use_application_options="true"/>
|
||||
<library name="encoder" location="..\..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="../../library/network/protocol/http/http-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\library\network\protocol\http\http-safe.ecf" readonly="false"/>
|
||||
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
||||
<library name="uri_template" location="../../library/text/parser/uri_template/uri_template-safe.ecf" readonly="false"/>
|
||||
<library name="uri_template" location="..\..\library\text\parser\uri_template\uri_template-safe.ecf" readonly="false"/>
|
||||
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf" readonly="false" use_application_options="true"/>
|
||||
<cluster name="src" location="src\" recursive="true">
|
||||
</cluster>
|
||||
<cluster name="src" location="src\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="http_client" uuid="628F5A96-021B-4191-926B-B3BF49272866" library_target="http_client">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="http_client" uuid="628F5A96-021B-4191-926B-B3BF49272866" library_target="http_client">
|
||||
<target name="http_client">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
|
||||
15
library/network/http_client/package.iron
Normal file
15
library/network/http_client/package.iron
Normal file
@@ -0,0 +1,15 @@
|
||||
package http_client
|
||||
|
||||
project
|
||||
http_client = "http_client-safe.ecf"
|
||||
http_client = "http_client.ecf"
|
||||
|
||||
note
|
||||
-- title:
|
||||
-- description:
|
||||
-- tags:
|
||||
-- license:
|
||||
-- copyright:
|
||||
-- link[doc]: "Documentation" http://
|
||||
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="conneg" uuid="D15DC4C4-D74F-4E4B-B4B1-2B03A35A284D" library_target="conneg">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="conneg" uuid="D15DC4C4-D74F-4E4B-B4B1-2B03A35A284D" library_target="conneg">
|
||||
<target name="conneg">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -18,7 +18,6 @@
|
||||
<exclude>/implementation</exclude>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
<cluster name="conneg_imp" location=".\src\implementation" recursive="true" hidden="true">
|
||||
</cluster>
|
||||
<cluster name="conneg_imp" location=".\src\implementation\" recursive="true" hidden="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
15
library/network/protocol/content_negotiation/package.iron
Normal file
15
library/network/protocol/content_negotiation/package.iron
Normal file
@@ -0,0 +1,15 @@
|
||||
package content_negotiation
|
||||
|
||||
project
|
||||
conneg = "conneg-safe.ecf"
|
||||
conneg = "conneg.ecf"
|
||||
|
||||
note
|
||||
-- title:
|
||||
-- description:
|
||||
-- tags:
|
||||
-- license:
|
||||
-- copyright:
|
||||
-- link[doc]: "Documentation" http://
|
||||
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="http" uuid="F8BE3C55-88E8-4103-A936-B1E5CB1D330E" library_target="http">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="http" uuid="F8BE3C55-88E8-4103-A936-B1E5CB1D330E" library_target="http">
|
||||
<target name="http">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
|
||||
15
library/network/protocol/http/package.iron
Normal file
15
library/network/protocol/http/package.iron
Normal file
@@ -0,0 +1,15 @@
|
||||
package http
|
||||
|
||||
project
|
||||
http = "http-safe.ecf"
|
||||
http = "http.ecf"
|
||||
|
||||
note
|
||||
-- title:
|
||||
-- description:
|
||||
-- tags:
|
||||
-- license:
|
||||
-- copyright:
|
||||
-- link[doc]: "Documentation" http://
|
||||
|
||||
end
|
||||
@@ -1,8 +1,9 @@
|
||||
note
|
||||
description: "[
|
||||
The class provides an easy way to build HTTP header.
|
||||
The class represents a HTTP header, and it provides simple routine
|
||||
to build it.
|
||||
|
||||
You will also find some helper feature to help coding most common usage
|
||||
You will also find some helper features to help coding most common usages
|
||||
|
||||
Please, have a look at constants classes such as
|
||||
HTTP_MIME_TYPES
|
||||
@@ -24,6 +25,8 @@ class
|
||||
inherit
|
||||
ITERABLE [READABLE_STRING_8]
|
||||
|
||||
HTTP_HEADER_MODIFIER
|
||||
|
||||
create
|
||||
make,
|
||||
make_with_count,
|
||||
@@ -116,6 +119,8 @@ feature -- Access
|
||||
result_has_single_ending_cr_lf: Result.count >= 4 implies not Result.substring (Result.count - 3, Result.count).same_string ("%R%N%R%N")
|
||||
end
|
||||
|
||||
feature -- Conversion
|
||||
|
||||
to_name_value_iterable: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]
|
||||
-- Iterable representation of the header entries.
|
||||
local
|
||||
@@ -132,7 +137,7 @@ feature -- Access
|
||||
Result := res
|
||||
end
|
||||
|
||||
feature -- Conversion
|
||||
feature --
|
||||
|
||||
append_string_to (a_result: STRING_8)
|
||||
-- Append current as string representation to `a_result'
|
||||
@@ -250,60 +255,6 @@ feature -- Header: merging
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has, has_header_named (a_name: READABLE_STRING_8): BOOLEAN
|
||||
-- Has header item for `n'?
|
||||
do
|
||||
Result := across headers as c some has_same_header_name (c.item, a_name) end
|
||||
end
|
||||
|
||||
has_content_length: BOOLEAN
|
||||
-- Has header "Content-Length"
|
||||
do
|
||||
Result := has_header_named ({HTTP_HEADER_NAMES}.header_content_length)
|
||||
end
|
||||
|
||||
has_content_type: BOOLEAN
|
||||
-- Has header "Content-Type"
|
||||
do
|
||||
Result := has_header_named ({HTTP_HEADER_NAMES}.header_content_type)
|
||||
end
|
||||
|
||||
has_transfer_encoding_chunked: BOOLEAN
|
||||
-- Has "Transfer-Encoding: chunked" header
|
||||
do
|
||||
if has_header_named ({HTTP_HEADER_NAMES}.header_transfer_encoding) then
|
||||
Result := attached header_named_value ({HTTP_HEADER_NAMES}.header_transfer_encoding) as v and then v.same_string (str_chunked)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
header_named_value (a_name: READABLE_STRING_8): detachable STRING_8
|
||||
-- First header item found for `a_name' if any
|
||||
require
|
||||
has_header: has_header_named (a_name)
|
||||
local
|
||||
n: INTEGER
|
||||
l_line: READABLE_STRING_8
|
||||
do
|
||||
n := a_name.count
|
||||
|
||||
across
|
||||
headers as ic
|
||||
until
|
||||
Result /= Void
|
||||
loop
|
||||
l_line := ic.item
|
||||
if has_same_header_name (l_line, a_name) then
|
||||
Result := l_line.substring (n + 2, l_line.count)
|
||||
Result.left_adjust
|
||||
Result.right_adjust
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Removal
|
||||
|
||||
remove_header_named (a_name: READABLE_STRING_8)
|
||||
@@ -334,375 +285,16 @@ feature -- Header change: general
|
||||
-- Add header `h'
|
||||
-- if it already exists, there will be multiple header with same name
|
||||
-- which can also be valid
|
||||
require
|
||||
h_not_empty: not h.is_empty
|
||||
do
|
||||
headers.force (h)
|
||||
end
|
||||
|
||||
put_header (h: READABLE_STRING_8)
|
||||
-- Add header `h' or replace existing header of same header name
|
||||
require
|
||||
h_not_empty: not h.is_empty
|
||||
do
|
||||
force_header_by_name (header_name_colon (h), h)
|
||||
end
|
||||
|
||||
add_header_key_value (k,v: READABLE_STRING_8)
|
||||
-- Add header `k:v'.
|
||||
-- If it already exists, there will be multiple header with same name
|
||||
-- which can also be valid
|
||||
local
|
||||
s: STRING_8
|
||||
do
|
||||
create s.make (k.count + 2 + v.count)
|
||||
s.append (k)
|
||||
s.append (colon_space)
|
||||
s.append (v)
|
||||
add_header (s)
|
||||
ensure
|
||||
added: has_header_named (k)
|
||||
end
|
||||
|
||||
put_header_key_value (k,v: READABLE_STRING_8)
|
||||
-- Add header `k:v', or replace existing header of same header name/key
|
||||
local
|
||||
s: STRING_8
|
||||
do
|
||||
create s.make (k.count + 2 + v.count)
|
||||
s.append (k)
|
||||
s.append (colon_space)
|
||||
s.append (v)
|
||||
put_header (s)
|
||||
ensure
|
||||
added: has_header_named (k)
|
||||
end
|
||||
|
||||
put_header_key_values (k: READABLE_STRING_8; a_values: ITERABLE [READABLE_STRING_8]; a_separator: detachable READABLE_STRING_8)
|
||||
-- Add header `k: a_values', or replace existing header of same header values/key.
|
||||
-- Use `comma_space' as default separator if `a_separator' is Void or empty.
|
||||
local
|
||||
s: STRING_8
|
||||
l_separator: READABLE_STRING_8
|
||||
do
|
||||
if a_separator /= Void and then not a_separator.is_empty then
|
||||
l_separator := a_separator
|
||||
else
|
||||
l_separator := comma_space
|
||||
end
|
||||
create s.make_empty
|
||||
across
|
||||
a_values as c
|
||||
loop
|
||||
if not s.is_empty then
|
||||
s.append_string (l_separator)
|
||||
end
|
||||
s.append (c.item)
|
||||
end
|
||||
if not s.is_empty then
|
||||
put_header_key_value (k, s)
|
||||
end
|
||||
ensure
|
||||
added: has_header_named (k)
|
||||
end
|
||||
|
||||
feature -- Content related header
|
||||
|
||||
put_content_type (t: READABLE_STRING_8)
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t)
|
||||
end
|
||||
|
||||
add_content_type (t: READABLE_STRING_8)
|
||||
-- same as `put_content_type', but allow multiple definition of "Content-Type"
|
||||
do
|
||||
add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t)
|
||||
end
|
||||
|
||||
put_content_type_with_parameters (t: READABLE_STRING_8; a_params: detachable ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
|
||||
local
|
||||
s: STRING_8
|
||||
do
|
||||
if a_params /= Void and then not a_params.is_empty then
|
||||
create s.make_from_string (t)
|
||||
across
|
||||
a_params as p
|
||||
loop
|
||||
if attached p.item as nv then
|
||||
s.append_character (';')
|
||||
s.append_character (' ')
|
||||
s.append (nv.name)
|
||||
s.append_character ('=')
|
||||
s.append_character ('%"')
|
||||
s.append (nv.value)
|
||||
s.append_character ('%"')
|
||||
end
|
||||
end
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, s)
|
||||
else
|
||||
put_content_type (t)
|
||||
end
|
||||
end
|
||||
|
||||
add_content_type_with_parameters (t: READABLE_STRING_8; a_params: detachable ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
|
||||
local
|
||||
s: STRING_8
|
||||
do
|
||||
if a_params /= Void and then not a_params.is_empty then
|
||||
create s.make_from_string (t)
|
||||
across
|
||||
a_params as p
|
||||
loop
|
||||
if attached p.item as nv then
|
||||
s.append_character (';')
|
||||
s.append_character (' ')
|
||||
s.append (nv.name)
|
||||
s.append_character ('=')
|
||||
s.append_character ('%"')
|
||||
s.append (nv.value)
|
||||
s.append_character ('%"')
|
||||
end
|
||||
end
|
||||
add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, s)
|
||||
else
|
||||
add_content_type (t)
|
||||
end
|
||||
end
|
||||
|
||||
put_content_type_with_charset (t: READABLE_STRING_8; c: READABLE_STRING_8)
|
||||
do
|
||||
put_content_type_with_parameters (t, <<["charset", c]>>)
|
||||
end
|
||||
|
||||
add_content_type_with_charset (t: READABLE_STRING_8; c: READABLE_STRING_8)
|
||||
-- same as `put_content_type_with_charset', but allow multiple definition of "Content-Type"
|
||||
do
|
||||
add_content_type_with_parameters (t, <<["charset", c]>>)
|
||||
end
|
||||
|
||||
put_content_type_with_name (t: READABLE_STRING_8; n: READABLE_STRING_8)
|
||||
do
|
||||
put_content_type_with_parameters (t, <<["name", n]>>)
|
||||
end
|
||||
|
||||
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"
|
||||
do
|
||||
add_content_type_with_parameters (t, <<["name", n]>>)
|
||||
end
|
||||
|
||||
put_content_length (n: INTEGER)
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_length, n.out)
|
||||
end
|
||||
|
||||
put_content_transfer_encoding (a_mechanism: READABLE_STRING_8)
|
||||
-- Put "Content-Transfer-Encoding" header with for instance "binary"
|
||||
--| encoding := "Content-Transfer-Encoding" ":" mechanism
|
||||
--|
|
||||
--| mechanism := "7bit" ; case-insensitive
|
||||
--| / "quoted-printable"
|
||||
--| / "base64"
|
||||
--| / "8bit"
|
||||
--| / "binary"
|
||||
--| / x-token
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_transfer_encoding, a_mechanism)
|
||||
end
|
||||
|
||||
put_content_language (a_lang: READABLE_STRING_8)
|
||||
-- Put "Content-Language" header of value `a_lang'.
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_language, a_lang)
|
||||
end
|
||||
|
||||
put_content_encoding (a_enc: READABLE_STRING_8)
|
||||
-- Put "Content-Encoding" header of value `a_enc'.
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_encoding, a_enc)
|
||||
end
|
||||
|
||||
put_transfer_encoding (a_enc: READABLE_STRING_8)
|
||||
-- Put "Transfer-Encoding" header with for instance "chunked"
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_transfer_encoding, a_enc)
|
||||
end
|
||||
|
||||
put_transfer_encoding_binary
|
||||
-- Put "Transfer-Encoding: binary" header
|
||||
do
|
||||
put_transfer_encoding (str_binary)
|
||||
end
|
||||
|
||||
put_transfer_encoding_chunked
|
||||
-- Put "Transfer-Encoding: chunked" header
|
||||
do
|
||||
put_transfer_encoding (str_chunked)
|
||||
end
|
||||
|
||||
put_content_disposition (a_type: READABLE_STRING_8; a_params: detachable READABLE_STRING_8)
|
||||
-- Put "Content-Disposition" header
|
||||
--| See RFC2183
|
||||
--| disposition := "Content-Disposition" ":"
|
||||
--| disposition-type
|
||||
--| *(";" disposition-parm)
|
||||
--| disposition-type := "inline"
|
||||
--| / "attachment"
|
||||
--| / extension-token
|
||||
--| ; values are not case-sensitive
|
||||
--| disposition-parm := filename-parm
|
||||
--| / creation-date-parm
|
||||
--| / modification-date-parm
|
||||
--| / read-date-parm
|
||||
--| / size-parm
|
||||
--| / parameter
|
||||
--| filename-parm := "filename" "=" value
|
||||
--| creation-date-parm := "creation-date" "=" quoted-date-time
|
||||
--| modification-date-parm := "modification-date" "=" quoted-date-time
|
||||
--| read-date-parm := "read-date" "=" quoted-date-time
|
||||
--| size-parm := "size" "=" 1*DIGIT
|
||||
--| quoted-date-time := quoted-string
|
||||
--| ; contents MUST be an RFC 822 `date-time'
|
||||
--| ; numeric timezones (+HHMM or -HHMM) MUST be used
|
||||
do
|
||||
if a_params /= Void then
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_disposition, a_type + semi_colon_space + a_params)
|
||||
else
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_disposition, a_type)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Content-type helpers
|
||||
|
||||
put_content_type_text_css do put_content_type ({HTTP_MIME_TYPES}.text_css) end
|
||||
put_content_type_text_csv do put_content_type ({HTTP_MIME_TYPES}.text_csv) end
|
||||
put_content_type_text_html do put_content_type ({HTTP_MIME_TYPES}.text_html) end
|
||||
put_content_type_text_javascript do put_content_type ({HTTP_MIME_TYPES}.text_javascript) end
|
||||
put_content_type_text_json do put_content_type ({HTTP_MIME_TYPES}.text_json) end
|
||||
put_content_type_text_plain do put_content_type ({HTTP_MIME_TYPES}.text_plain) end
|
||||
put_content_type_text_xml do put_content_type ({HTTP_MIME_TYPES}.text_xml) end
|
||||
|
||||
put_content_type_application_json do put_content_type ({HTTP_MIME_TYPES}.application_json) end
|
||||
put_content_type_application_javascript do put_content_type ({HTTP_MIME_TYPES}.application_javascript) end
|
||||
put_content_type_application_zip do put_content_type ({HTTP_MIME_TYPES}.application_zip) end
|
||||
put_content_type_application_pdf do put_content_type ({HTTP_MIME_TYPES}.application_pdf) end
|
||||
|
||||
put_content_type_image_gif do put_content_type ({HTTP_MIME_TYPES}.image_gif) end
|
||||
put_content_type_image_png do put_content_type ({HTTP_MIME_TYPES}.image_png) end
|
||||
put_content_type_image_jpg do put_content_type ({HTTP_MIME_TYPES}.image_jpg) end
|
||||
put_content_type_image_svg_xml do put_content_type ({HTTP_MIME_TYPES}.image_svg_xml) end
|
||||
|
||||
put_content_type_message_http do put_content_type ({HTTP_MIME_TYPES}.message_http) end
|
||||
|
||||
put_content_type_multipart_mixed do put_content_type ({HTTP_MIME_TYPES}.multipart_mixed) end
|
||||
put_content_type_multipart_alternative do put_content_type ({HTTP_MIME_TYPES}.multipart_alternative) end
|
||||
put_content_type_multipart_related do put_content_type ({HTTP_MIME_TYPES}.multipart_related) end
|
||||
put_content_type_multipart_form_data do put_content_type ({HTTP_MIME_TYPES}.multipart_form_data) end
|
||||
put_content_type_multipart_signed do put_content_type ({HTTP_MIME_TYPES}.multipart_signed) end
|
||||
put_content_type_multipart_encrypted do put_content_type ({HTTP_MIME_TYPES}.multipart_encrypted) end
|
||||
put_content_type_application_x_www_form_encoded do put_content_type ({HTTP_MIME_TYPES}.application_x_www_form_encoded) end
|
||||
|
||||
feature -- Cross-Origin Resource Sharing
|
||||
|
||||
put_access_control_allow_origin (s: READABLE_STRING_8)
|
||||
-- Put "Access-Control-Allow-Origin" header.
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_origin, s)
|
||||
end
|
||||
|
||||
put_access_control_allow_all_origin
|
||||
-- Put "Access-Control-Allow-Origin: *" header.
|
||||
do
|
||||
put_access_control_allow_origin ("*")
|
||||
end
|
||||
|
||||
put_access_control_allow_methods (a_methods: ITERABLE [READABLE_STRING_8])
|
||||
-- If `a_methods' is not empty, put `Access-Control-Allow-Methods' header with list `a_methods' of methods
|
||||
do
|
||||
put_header_key_values ({HTTP_HEADER_NAMES}.header_access_control_allow_methods, a_methods, Void)
|
||||
end
|
||||
|
||||
put_access_control_allow_headers (s: READABLE_STRING_8)
|
||||
-- Put "Access-Control-Allow-Headers" header.
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_headers, s)
|
||||
end
|
||||
|
||||
feature -- Method related
|
||||
|
||||
put_allow (a_methods: ITERABLE [READABLE_STRING_8])
|
||||
-- If `a_methods' is not empty, put `Allow' header with list `a_methods' of methods
|
||||
do
|
||||
put_header_key_values ({HTTP_HEADER_NAMES}.header_allow, a_methods, Void)
|
||||
end
|
||||
|
||||
feature -- Date
|
||||
|
||||
put_date (s: READABLE_STRING_8)
|
||||
-- Put "Date: " header
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_date, s)
|
||||
end
|
||||
|
||||
put_current_date
|
||||
-- Put current date time with "Date" header
|
||||
do
|
||||
put_utc_date (create {DATE_TIME}.make_now_utc)
|
||||
end
|
||||
|
||||
put_utc_date (a_utc_date: DATE_TIME)
|
||||
-- Put UTC date time `dt' with "Date" header
|
||||
do
|
||||
put_date (date_to_rfc1123_http_date_format (a_utc_date))
|
||||
end
|
||||
|
||||
put_last_modified (a_utc_date: DATE_TIME)
|
||||
-- Put UTC date time `dt' with "Date" header
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_last_modified, date_to_rfc1123_http_date_format (a_utc_date))
|
||||
end
|
||||
|
||||
feature -- Authorization
|
||||
|
||||
put_authorization (s: READABLE_STRING_8)
|
||||
-- Put authorization `s' with "Authorization" header
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_authorization, s)
|
||||
end
|
||||
|
||||
feature -- Others
|
||||
|
||||
put_expires (sec: INTEGER)
|
||||
do
|
||||
put_expires_string (sec.out)
|
||||
end
|
||||
|
||||
put_expires_string (s: STRING)
|
||||
do
|
||||
put_header_key_value ("Expires", s)
|
||||
end
|
||||
|
||||
put_expires_date (a_utc_date: DATE_TIME)
|
||||
do
|
||||
put_header_key_value ("Expires", date_to_rfc1123_http_date_format (a_utc_date))
|
||||
end
|
||||
|
||||
put_cache_control (s: READABLE_STRING_8)
|
||||
-- `s' could be for instance "no-cache, must-revalidate"
|
||||
do
|
||||
put_header_key_value ("Cache-Control", s)
|
||||
end
|
||||
|
||||
put_pragma (s: READABLE_STRING_8)
|
||||
do
|
||||
put_header_key_value ("Pragma", s)
|
||||
end
|
||||
|
||||
put_pragma_no_cache
|
||||
do
|
||||
put_pragma ("no-cache")
|
||||
end
|
||||
|
||||
feature -- Redirection
|
||||
|
||||
remove_location
|
||||
@@ -711,79 +303,7 @@ feature -- Redirection
|
||||
remove_header_named ({HTTP_HEADER_NAMES}.header_location)
|
||||
end
|
||||
|
||||
put_location (a_location: READABLE_STRING_8)
|
||||
-- Tell the client the new location `a_location'
|
||||
require
|
||||
a_location_valid: not a_location.is_empty
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_location, a_location)
|
||||
end
|
||||
|
||||
put_refresh (a_location: READABLE_STRING_8; a_timeout_in_seconds: INTEGER)
|
||||
-- Tell the client to refresh page with `a_location' after `a_timeout_in_seconds' in seconds
|
||||
require
|
||||
a_location_valid: not a_location.is_empty
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_refresh, a_timeout_in_seconds.out + "; url=" + a_location)
|
||||
end
|
||||
|
||||
feature -- Cookie
|
||||
|
||||
put_cookie (key, value: READABLE_STRING_8; expiration, path, domain: detachable READABLE_STRING_8; secure, http_only: BOOLEAN)
|
||||
-- Set a cookie on the client's machine
|
||||
-- with key 'key' and value 'value'.
|
||||
-- Note: you should avoid using "localhost" as `domain' for local cookies
|
||||
-- since they are not always handled by browser (for instance Chrome)
|
||||
require
|
||||
make_sense: (key /= Void and value /= Void) and then (not key.is_empty and not value.is_empty)
|
||||
domain_without_port_info: domain /= Void implies domain.index_of (':', 1) = 0
|
||||
local
|
||||
s: STRING
|
||||
do
|
||||
s := {HTTP_HEADER_NAMES}.header_set_cookie + colon_space + key + "=" + value
|
||||
if
|
||||
domain /= Void and then not domain.same_string ("localhost")
|
||||
then
|
||||
s.append ("; Domain=")
|
||||
s.append (domain)
|
||||
end
|
||||
if path /= Void then
|
||||
s.append ("; Path=")
|
||||
s.append (path)
|
||||
end
|
||||
if expiration /= Void then
|
||||
s.append ("; Expires=")
|
||||
s.append (expiration)
|
||||
end
|
||||
if secure then
|
||||
s.append ("; Secure")
|
||||
end
|
||||
if http_only then
|
||||
s.append ("; HttpOnly")
|
||||
end
|
||||
add_header (s)
|
||||
end
|
||||
|
||||
put_cookie_with_expiration_date (key, value: READABLE_STRING_8; expiration: DATE_TIME; path, domain: detachable READABLE_STRING_8; secure, http_only: BOOLEAN)
|
||||
-- Set a cookie on the client's machine
|
||||
-- with key 'key' and value 'value'.
|
||||
require
|
||||
make_sense: (key /= Void and value /= Void) and then (not key.is_empty and not value.is_empty)
|
||||
do
|
||||
put_cookie (key, value, date_to_rfc1123_http_date_format (expiration), path, domain, secure, http_only)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: Header
|
||||
|
||||
has_same_header_name (h: READABLE_STRING_8; a_name: READABLE_STRING_8): BOOLEAN
|
||||
-- Header line `h' has same name as `a_name' ?
|
||||
do
|
||||
if h.starts_with (a_name) then
|
||||
if h.valid_index (a_name.count + 1) then
|
||||
Result := h[a_name.count + 1] = ':'
|
||||
end
|
||||
end
|
||||
end
|
||||
feature {NONE} -- Implementation: Header change
|
||||
|
||||
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'
|
||||
@@ -811,6 +331,27 @@ feature {NONE} -- Implementation: Header
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: Header conversion
|
||||
|
||||
append_line_to (a_line: READABLE_STRING_8; h: STRING_8)
|
||||
-- Append header line `a_line' to string `h'.
|
||||
--| this is used to build the header text
|
||||
require
|
||||
not_ending_with_new_line: not a_line.ends_with_general ("%N")
|
||||
do
|
||||
h.append_string (a_line)
|
||||
append_end_of_line_to (h)
|
||||
end
|
||||
|
||||
append_end_of_line_to (h: STRING_8)
|
||||
-- Append the CRLN end of header line to string `h'.
|
||||
do
|
||||
h.append_character ('%R')
|
||||
h.append_character ('%N')
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: Header queries
|
||||
|
||||
header_name_colon (h: READABLE_STRING_8): detachable STRING_8
|
||||
-- If any, header's name with colon
|
||||
--| ex: for "Foo-bar: something", this will return "Foo-bar:"
|
||||
@@ -870,51 +411,6 @@ feature {NONE} -- Implementation: Header
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
append_line_to (s: READABLE_STRING_8; h: STRING_8)
|
||||
do
|
||||
h.append_string (s)
|
||||
append_end_of_line_to (h)
|
||||
end
|
||||
|
||||
append_end_of_line_to (h: STRING_8)
|
||||
do
|
||||
h.append_character ('%R')
|
||||
h.append_character ('%N')
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
date_to_rfc1123_http_date_format (dt: DATE_TIME): STRING_8
|
||||
-- String representation of `dt' using the RFC 1123
|
||||
local
|
||||
d: HTTP_DATE
|
||||
do
|
||||
create d.make_from_date_time (dt)
|
||||
Result := d.string
|
||||
end
|
||||
|
||||
feature {NONE} -- Constants
|
||||
|
||||
str_binary: STRING = "binary"
|
||||
str_chunked: STRING = "chunked"
|
||||
|
||||
colon_space: IMMUTABLE_STRING_8
|
||||
once
|
||||
create Result.make_from_string (": ")
|
||||
end
|
||||
|
||||
semi_colon_space: IMMUTABLE_STRING_8
|
||||
once
|
||||
create Result.make_from_string ("; ")
|
||||
end
|
||||
|
||||
comma_space: IMMUTABLE_STRING_8
|
||||
once
|
||||
create Result.make_from_string (", ")
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
667
library/network/protocol/http/src/http_header_modifier.e
Normal file
667
library/network/protocol/http/src/http_header_modifier.e
Normal file
@@ -0,0 +1,667 @@
|
||||
note
|
||||
description: "[
|
||||
The class provides an easy way to build and modify HTTP header text
|
||||
thanks to add_header (..) and put_header (..)
|
||||
|
||||
You will also find some helper features to help coding most common usages
|
||||
|
||||
Please, have a look at constants classes such as
|
||||
HTTP_MIME_TYPES
|
||||
HTTP_HEADER_NAMES
|
||||
HTTP_STATUS_CODE
|
||||
HTTP_REQUEST_METHODS
|
||||
(or HTTP_CONSTANTS which groups them for convenience)
|
||||
|
||||
Note the return status code is not part of the HTTP header
|
||||
]"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
HTTP_HEADER_MODIFIER
|
||||
|
||||
inherit
|
||||
ITERABLE [READABLE_STRING_8]
|
||||
|
||||
feature -- Access: deferred
|
||||
|
||||
new_cursor: INDEXABLE_ITERATION_CURSOR [READABLE_STRING_8]
|
||||
-- Fresh cursor associated with current structure.
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Header change: deferred
|
||||
|
||||
add_header (h: READABLE_STRING_8)
|
||||
-- Add header `h'
|
||||
-- if it already exists, there will be multiple header with same name
|
||||
-- which can also be valid
|
||||
require
|
||||
h_not_empty: h /= Void and then not h.is_empty
|
||||
deferred
|
||||
end
|
||||
|
||||
put_header (h: READABLE_STRING_8)
|
||||
-- Add header `h' or replace existing header of same header name
|
||||
require
|
||||
h_not_empty: h /= Void and then not h.is_empty
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has, has_header_named (a_name: READABLE_STRING_8): BOOLEAN
|
||||
-- Has header item for `n'?
|
||||
local
|
||||
ic: like new_cursor
|
||||
do
|
||||
from
|
||||
ic := new_cursor
|
||||
until
|
||||
ic.after or Result
|
||||
loop
|
||||
Result := has_same_header_name (ic.item, a_name)
|
||||
ic.forth
|
||||
end
|
||||
end
|
||||
|
||||
has_content_length: BOOLEAN
|
||||
-- Has header "Content-Length"
|
||||
do
|
||||
Result := has_header_named ({HTTP_HEADER_NAMES}.header_content_length)
|
||||
end
|
||||
|
||||
has_content_type: BOOLEAN
|
||||
-- Has header "Content-Type"
|
||||
do
|
||||
Result := has_header_named ({HTTP_HEADER_NAMES}.header_content_type)
|
||||
end
|
||||
|
||||
has_transfer_encoding_chunked: BOOLEAN
|
||||
-- Has "Transfer-Encoding: chunked" header
|
||||
do
|
||||
if has_header_named ({HTTP_HEADER_NAMES}.header_transfer_encoding) then
|
||||
Result := attached item ({HTTP_HEADER_NAMES}.header_transfer_encoding) as v and then v.same_string (str_chunked)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
item alias "[]" (a_header_name: READABLE_STRING_8): detachable READABLE_STRING_8 assign force
|
||||
-- First header item found for `a_name' if any
|
||||
local
|
||||
res: STRING_8
|
||||
n: INTEGER
|
||||
l_line: READABLE_STRING_8
|
||||
ic: like new_cursor
|
||||
do
|
||||
n := a_header_name.count
|
||||
|
||||
from
|
||||
ic := new_cursor
|
||||
until
|
||||
ic.after or Result /= Void
|
||||
loop
|
||||
l_line := ic.item
|
||||
if has_same_header_name (l_line, a_header_name) then
|
||||
res := l_line.substring (n + 2, l_line.count)
|
||||
res.left_adjust
|
||||
res.right_adjust
|
||||
Result := res
|
||||
end
|
||||
ic.forth
|
||||
end
|
||||
end
|
||||
|
||||
header_named_value (a_name: READABLE_STRING_8): like item
|
||||
-- First header item found for `a_name' if any
|
||||
obsolete
|
||||
"Use `item' [2014-03]"
|
||||
do
|
||||
Result := item (a_name)
|
||||
end
|
||||
|
||||
feature -- Header change: general
|
||||
|
||||
force (a_value: detachable READABLE_STRING_8; a_header_name: READABLE_STRING_8)
|
||||
-- Put header `a_header_name:a_value' or replace existing header of name `a_header_name'.
|
||||
--| this is used as assigner for `item'
|
||||
do
|
||||
if a_value = Void then
|
||||
put_header_key_value (a_header_name, "")
|
||||
else
|
||||
put_header_key_value (a_header_name, a_value)
|
||||
end
|
||||
end
|
||||
|
||||
add_header_key_value (a_header_name, a_value: READABLE_STRING_8)
|
||||
-- Add header `a_header_name:a_value'.
|
||||
-- If it already exists, there will be multiple header with same name
|
||||
-- which can also be valid
|
||||
local
|
||||
s: STRING_8
|
||||
do
|
||||
create s.make (a_header_name.count + 2 + a_value.count)
|
||||
s.append (a_header_name)
|
||||
s.append (colon_space)
|
||||
s.append (a_value)
|
||||
add_header (s)
|
||||
ensure
|
||||
added: has_header_named (a_header_name)
|
||||
end
|
||||
|
||||
put_header_key_value (a_header_name, a_value: READABLE_STRING_8)
|
||||
-- Add header `a_header_name:a_value', or replace existing header of same header name/key
|
||||
local
|
||||
s: STRING_8
|
||||
do
|
||||
create s.make (a_header_name.count + 2 + a_value.count)
|
||||
s.append (a_header_name)
|
||||
s.append (colon_space)
|
||||
s.append (a_value)
|
||||
put_header (s)
|
||||
ensure
|
||||
added: has_header_named (a_header_name)
|
||||
end
|
||||
|
||||
put_header_key_values (a_header_name: READABLE_STRING_8; a_values: ITERABLE [READABLE_STRING_8]; a_separator: detachable READABLE_STRING_8)
|
||||
-- Add header `a_header_name: a_values', or replace existing header of same header values/key.
|
||||
-- Use `comma_space' as default separator if `a_separator' is Void or empty.
|
||||
local
|
||||
s: STRING_8
|
||||
l_separator: READABLE_STRING_8
|
||||
do
|
||||
if a_separator /= Void and then not a_separator.is_empty then
|
||||
l_separator := a_separator
|
||||
else
|
||||
l_separator := comma_space
|
||||
end
|
||||
create s.make_empty
|
||||
across
|
||||
a_values as c
|
||||
loop
|
||||
if not s.is_empty then
|
||||
s.append_string (l_separator)
|
||||
end
|
||||
s.append (c.item)
|
||||
end
|
||||
if not s.is_empty then
|
||||
put_header_key_value (a_header_name, s)
|
||||
end
|
||||
ensure
|
||||
added: has_header_named (a_header_name)
|
||||
end
|
||||
|
||||
feature -- Content related header
|
||||
|
||||
put_content_type (a_content_type: READABLE_STRING_8)
|
||||
-- Put header line "Content-Type:" + type `a_content_type'
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, a_content_type)
|
||||
end
|
||||
|
||||
add_content_type (a_content_type: READABLE_STRING_8)
|
||||
-- same as `put_content_type', but allow multiple definition of "Content-Type"
|
||||
do
|
||||
add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, a_content_type)
|
||||
end
|
||||
|
||||
put_content_type_with_parameters (a_content_type: READABLE_STRING_8; a_params: detachable ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
|
||||
-- Put header line "Content-Type:" + type `a_content_type' and extra paramaters `a_params'
|
||||
--| note: see `put_content_type_with_charset' for examples.
|
||||
local
|
||||
s: STRING_8
|
||||
do
|
||||
if a_params /= Void and then not a_params.is_empty then
|
||||
create s.make_from_string (a_content_type)
|
||||
across
|
||||
a_params as p
|
||||
loop
|
||||
if attached p.item as nv then
|
||||
s.append_character (';')
|
||||
s.append_character (' ')
|
||||
s.append (nv.name)
|
||||
s.append_character ('=')
|
||||
s.append_character ('%"')
|
||||
s.append (nv.value)
|
||||
s.append_character ('%"')
|
||||
end
|
||||
end
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, s)
|
||||
else
|
||||
put_content_type (a_content_type)
|
||||
end
|
||||
end
|
||||
|
||||
add_content_type_with_parameters (a_content_type: READABLE_STRING_8; a_params: detachable ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
|
||||
-- Add header line "Content-Type:" + type `a_content_type' and extra paramaters `a_params'.
|
||||
--| note: see `put_content_type_with_charset' for examples.
|
||||
local
|
||||
s: STRING_8
|
||||
do
|
||||
if a_params /= Void and then not a_params.is_empty then
|
||||
create s.make_from_string (a_content_type)
|
||||
across
|
||||
a_params as p
|
||||
loop
|
||||
if attached p.item as nv then
|
||||
s.append_character (';')
|
||||
s.append_character (' ')
|
||||
s.append (nv.name)
|
||||
s.append_character ('=')
|
||||
s.append_character ('%"')
|
||||
s.append (nv.value)
|
||||
s.append_character ('%"')
|
||||
end
|
||||
end
|
||||
add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, s)
|
||||
else
|
||||
add_content_type (a_content_type)
|
||||
end
|
||||
end
|
||||
|
||||
put_content_type_with_charset (a_content_type: READABLE_STRING_8; a_charset: READABLE_STRING_8)
|
||||
-- Put content type `a_content_type' with `a_charset' as "charset" parameter.
|
||||
do
|
||||
put_content_type_with_parameters (a_content_type, <<["charset", a_charset]>>)
|
||||
end
|
||||
|
||||
add_content_type_with_charset (a_content_type: READABLE_STRING_8; a_charset: READABLE_STRING_8)
|
||||
-- Same as `put_content_type_with_charset', but allow multiple definition of "Content-Type".
|
||||
do
|
||||
add_content_type_with_parameters (a_content_type, <<["charset", a_charset]>>)
|
||||
end
|
||||
|
||||
put_content_type_with_name (a_content_type: READABLE_STRING_8; a_name: READABLE_STRING_8)
|
||||
-- Put content type `a_content_type' with `a_name' as "name" parameter.
|
||||
do
|
||||
put_content_type_with_parameters (a_content_type, <<["name", a_name]>>)
|
||||
end
|
||||
|
||||
add_content_type_with_name (a_content_type: READABLE_STRING_8; a_name: READABLE_STRING_8)
|
||||
-- same as `put_content_type_with_name', but allow multiple definition of "Content-Type"
|
||||
do
|
||||
add_content_type_with_parameters (a_content_type, <<["name", a_name]>>)
|
||||
end
|
||||
|
||||
put_content_length (a_length: INTEGER)
|
||||
-- Put "Content-Length:" + length `a_length'.
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_length, a_length.out)
|
||||
end
|
||||
|
||||
put_content_transfer_encoding (a_mechanism: READABLE_STRING_8)
|
||||
-- Put "Content-Transfer-Encoding" header with `a_mechanism'
|
||||
--| encoding := "Content-Transfer-Encoding" ":" mechanism
|
||||
--|
|
||||
--| mechanism := "7bit" ; case-insensitive
|
||||
--| / "quoted-printable"
|
||||
--| / "base64"
|
||||
--| / "8bit"
|
||||
--| / "binary"
|
||||
--| / x-token
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_transfer_encoding, a_mechanism)
|
||||
end
|
||||
|
||||
put_content_language (a_lang: READABLE_STRING_8)
|
||||
-- Put "Content-Language" header of value `a_lang'.
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_language, a_lang)
|
||||
end
|
||||
|
||||
put_content_encoding (a_encoding: READABLE_STRING_8)
|
||||
-- Put "Content-Encoding" header of value `a_encoding'.
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_encoding, a_encoding)
|
||||
end
|
||||
|
||||
put_transfer_encoding (a_encoding: READABLE_STRING_8)
|
||||
-- Put "Transfer-Encoding" header with `a_encoding' value.
|
||||
--| for instance "chunked"
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_transfer_encoding, a_encoding)
|
||||
end
|
||||
|
||||
put_transfer_encoding_binary
|
||||
-- Put "Transfer-Encoding: binary" header
|
||||
do
|
||||
put_transfer_encoding (str_binary)
|
||||
end
|
||||
|
||||
put_transfer_encoding_chunked
|
||||
-- Put "Transfer-Encoding: chunked" header
|
||||
do
|
||||
put_transfer_encoding (str_chunked)
|
||||
end
|
||||
|
||||
put_content_disposition (a_type: READABLE_STRING_8; a_params: detachable READABLE_STRING_8)
|
||||
-- Put "Content-Disposition" header
|
||||
--| See RFC2183
|
||||
--| disposition := "Content-Disposition" ":"
|
||||
--| disposition-type
|
||||
--| *(";" disposition-parm)
|
||||
--| disposition-type := "inline"
|
||||
--| / "attachment"
|
||||
--| / extension-token
|
||||
--| ; values are not case-sensitive
|
||||
--| disposition-parm := filename-parm
|
||||
--| / creation-date-parm
|
||||
--| / modification-date-parm
|
||||
--| / read-date-parm
|
||||
--| / size-parm
|
||||
--| / parameter
|
||||
--| filename-parm := "filename" "=" value
|
||||
--| creation-date-parm := "creation-date" "=" quoted-date-time
|
||||
--| modification-date-parm := "modification-date" "=" quoted-date-time
|
||||
--| read-date-parm := "read-date" "=" quoted-date-time
|
||||
--| size-parm := "size" "=" 1*DIGIT
|
||||
--| quoted-date-time := quoted-string
|
||||
--| ; contents MUST be an RFC 822 `date-time'
|
||||
--| ; numeric timezones (+HHMM or -HHMM) MUST be used
|
||||
do
|
||||
if a_params /= Void then
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_disposition, a_type + semi_colon_space + a_params)
|
||||
else
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_disposition, a_type)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Content-type helpers
|
||||
|
||||
put_content_type_text_css do put_content_type ({HTTP_MIME_TYPES}.text_css) end
|
||||
put_content_type_text_csv do put_content_type ({HTTP_MIME_TYPES}.text_csv) end
|
||||
put_content_type_text_html do put_content_type ({HTTP_MIME_TYPES}.text_html) end
|
||||
put_content_type_text_javascript do put_content_type ({HTTP_MIME_TYPES}.text_javascript) end
|
||||
put_content_type_text_json do put_content_type ({HTTP_MIME_TYPES}.text_json) end
|
||||
put_content_type_text_plain do put_content_type ({HTTP_MIME_TYPES}.text_plain) end
|
||||
put_content_type_text_xml do put_content_type ({HTTP_MIME_TYPES}.text_xml) end
|
||||
|
||||
put_content_type_application_json do put_content_type ({HTTP_MIME_TYPES}.application_json) end
|
||||
put_content_type_application_javascript do put_content_type ({HTTP_MIME_TYPES}.application_javascript) end
|
||||
put_content_type_application_zip do put_content_type ({HTTP_MIME_TYPES}.application_zip) end
|
||||
put_content_type_application_pdf do put_content_type ({HTTP_MIME_TYPES}.application_pdf) end
|
||||
|
||||
put_content_type_image_gif do put_content_type ({HTTP_MIME_TYPES}.image_gif) end
|
||||
put_content_type_image_png do put_content_type ({HTTP_MIME_TYPES}.image_png) end
|
||||
put_content_type_image_jpg do put_content_type ({HTTP_MIME_TYPES}.image_jpg) end
|
||||
put_content_type_image_svg_xml do put_content_type ({HTTP_MIME_TYPES}.image_svg_xml) end
|
||||
|
||||
put_content_type_message_http do put_content_type ({HTTP_MIME_TYPES}.message_http) end
|
||||
|
||||
put_content_type_multipart_mixed do put_content_type ({HTTP_MIME_TYPES}.multipart_mixed) end
|
||||
put_content_type_multipart_alternative do put_content_type ({HTTP_MIME_TYPES}.multipart_alternative) end
|
||||
put_content_type_multipart_related do put_content_type ({HTTP_MIME_TYPES}.multipart_related) end
|
||||
put_content_type_multipart_form_data do put_content_type ({HTTP_MIME_TYPES}.multipart_form_data) end
|
||||
put_content_type_multipart_signed do put_content_type ({HTTP_MIME_TYPES}.multipart_signed) end
|
||||
put_content_type_multipart_encrypted do put_content_type ({HTTP_MIME_TYPES}.multipart_encrypted) end
|
||||
put_content_type_application_x_www_form_encoded do put_content_type ({HTTP_MIME_TYPES}.application_x_www_form_encoded) end
|
||||
|
||||
put_content_type_utf_8_text_plain do put_content_type_with_charset ({HTTP_MIME_TYPES}.text_plain, "utf-8") end
|
||||
|
||||
feature -- Cross-Origin Resource Sharing
|
||||
|
||||
put_access_control_allow_origin (a_origin: READABLE_STRING_8)
|
||||
-- Put "Access-Control-Allow-Origin: " + `a_origin' header.
|
||||
-- `a_origin' specifies a URI that may access the resource
|
||||
--| for instance "http://example.com"
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_origin, a_origin)
|
||||
end
|
||||
|
||||
put_access_control_allow_all_origin
|
||||
-- Put "Access-Control-Allow-Origin: *" header.
|
||||
do
|
||||
put_access_control_allow_origin ("*")
|
||||
end
|
||||
|
||||
put_access_control_allow_credentials (b: BOOLEAN)
|
||||
-- Indicates whether or not the response to the request can be exposed when the credentials flag is true.
|
||||
-- When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials.
|
||||
-- Note that simple GET requests are not preflighted, and so if a request is made for a resource with credentials,
|
||||
-- if this header is not returned with the resource, the response is ignored by the browser and not returned to web content.
|
||||
-- ex: Access-Control-Allow-Credentials: true | false
|
||||
do
|
||||
if b then
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_Credentials, "true")
|
||||
else
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_Credentials, "false")
|
||||
end
|
||||
end
|
||||
|
||||
put_access_control_allow_methods (a_methods: ITERABLE [READABLE_STRING_8])
|
||||
-- If `a_methods' is not empty, put `Access-Control-Allow-Methods' header with list `a_methods' of methods
|
||||
-- `a_methods' specifies the method or methods allowed when accessing the resource.
|
||||
-- This is used in response to a preflight request.
|
||||
-- ex: Access-Control-Allow-Methods: <method>[, <method>]*
|
||||
do
|
||||
put_header_key_values ({HTTP_HEADER_NAMES}.header_access_control_allow_methods, a_methods, Void)
|
||||
end
|
||||
|
||||
put_access_control_allow_headers (a_headers: READABLE_STRING_8)
|
||||
-- Put "Access-Control-Allow-Headers" header. with value `a_headers'
|
||||
-- Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.
|
||||
-- ex: Access-Control-Allow-Headers: <field-name>[, <field-name>]*
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_access_control_allow_headers, a_headers)
|
||||
end
|
||||
|
||||
put_access_control_allow_iterable_headers (a_fields: ITERABLE [READABLE_STRING_8])
|
||||
-- Put "Access-Control-Allow-Headers" header. with value `a_headers'
|
||||
-- Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.
|
||||
-- ex: Access-Control-Allow-Headers: <field-name>[, <field-name>]*
|
||||
do
|
||||
put_header_key_values ({HTTP_HEADER_NAMES}.header_access_control_allow_headers, a_fields, Void)
|
||||
end
|
||||
|
||||
feature -- Method related
|
||||
|
||||
put_allow (a_methods: ITERABLE [READABLE_STRING_8])
|
||||
-- If `a_methods' is not empty, put `Allow' header with list `a_methods' of methods
|
||||
do
|
||||
put_header_key_values ({HTTP_HEADER_NAMES}.header_allow, a_methods, Void)
|
||||
end
|
||||
|
||||
feature -- Date
|
||||
|
||||
put_date (a_date: READABLE_STRING_8)
|
||||
-- Put "Date: " header
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_date, a_date)
|
||||
end
|
||||
|
||||
put_current_date
|
||||
-- Put current date time with "Date" header
|
||||
do
|
||||
put_utc_date (create {DATE_TIME}.make_now_utc)
|
||||
end
|
||||
|
||||
put_utc_date (a_utc_date: DATE_TIME)
|
||||
-- Put UTC date time `a_utc_date' with "Date" header
|
||||
-- using RFC1123 date formating.
|
||||
do
|
||||
put_date (date_to_rfc1123_http_date_format (a_utc_date))
|
||||
end
|
||||
|
||||
put_last_modified (a_utc_date: DATE_TIME)
|
||||
-- Put UTC date time `dt' with "Last-Modified" header
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_last_modified, date_to_rfc1123_http_date_format (a_utc_date))
|
||||
end
|
||||
|
||||
feature -- Authorization
|
||||
|
||||
put_authorization (a_authorization: READABLE_STRING_8)
|
||||
-- Put `a_authorization' with "Authorization" header
|
||||
-- The Authorization header is constructed as follows:
|
||||
-- 1. Username and password are combined into a string "username:password".
|
||||
-- 2. The resulting string literal is then encoded using Base64.
|
||||
-- 3. The authorization method and a space, i.e. "Basic " is then put before the encoded string.
|
||||
-- ex: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_authorization, a_authorization)
|
||||
end
|
||||
|
||||
feature -- Others
|
||||
|
||||
put_expires (a_seconds: INTEGER)
|
||||
-- Put "Expires" header to `a_seconds' seconds
|
||||
do
|
||||
put_expires_string (a_seconds.out)
|
||||
end
|
||||
|
||||
put_expires_string (a_expires: STRING)
|
||||
-- Put "Expires" header with `a_expires' string value
|
||||
do
|
||||
put_header_key_value ("Expires", a_expires)
|
||||
end
|
||||
|
||||
put_expires_date (a_utc_date: DATE_TIME)
|
||||
-- Put "Expires" header with UTC date time value
|
||||
-- formatted following RFC1123 specification.
|
||||
do
|
||||
put_header_key_value ("Expires", date_to_rfc1123_http_date_format (a_utc_date))
|
||||
end
|
||||
|
||||
put_cache_control (a_cache_control: READABLE_STRING_8)
|
||||
-- Put "Cache-Control" header with value `a_cache_control'
|
||||
--| note: ex "Cache-Control: no-cache, must-revalidate"
|
||||
do
|
||||
put_header_key_value ("Cache-Control", a_cache_control)
|
||||
end
|
||||
|
||||
put_pragma (a_pragma: READABLE_STRING_8)
|
||||
-- Put "Pragma" header with value `a_pragma'
|
||||
do
|
||||
put_header_key_value ("Pragma", a_pragma)
|
||||
end
|
||||
|
||||
put_pragma_no_cache
|
||||
-- Put "Pragma" header with "no-cache" a_pragma
|
||||
do
|
||||
put_pragma ("no-cache")
|
||||
end
|
||||
|
||||
feature -- Redirection
|
||||
|
||||
put_location (a_uri: READABLE_STRING_8)
|
||||
-- Tell the client the new location `a_uri'
|
||||
-- using "Location" header.
|
||||
require
|
||||
a_uri_valid: not a_uri.is_empty
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_location, a_uri)
|
||||
end
|
||||
|
||||
put_refresh (a_uri: READABLE_STRING_8; a_timeout_in_seconds: INTEGER)
|
||||
-- Tell the client to refresh page with `a_uri' after `a_timeout_in_seconds' in seconds
|
||||
-- using "Refresh" header.
|
||||
require
|
||||
a_uri_valid: not a_uri.is_empty
|
||||
do
|
||||
put_header_key_value ({HTTP_HEADER_NAMES}.header_refresh, a_timeout_in_seconds.out + "; url=" + a_uri)
|
||||
end
|
||||
|
||||
feature -- Cookie
|
||||
|
||||
put_cookie (key, value: READABLE_STRING_8; expiration, path, domain: detachable READABLE_STRING_8; secure, http_only: BOOLEAN)
|
||||
-- Set a cookie on the client's machine
|
||||
-- with key 'key' and value 'value'.
|
||||
-- Note: you should avoid using "localhost" as `domain' for local cookies
|
||||
-- since they are not always handled by browser (for instance Chrome)
|
||||
require
|
||||
make_sense: (key /= Void and value /= Void) and then (not key.is_empty and not value.is_empty)
|
||||
domain_without_port_info: domain /= Void implies domain.index_of (':', 1) = 0
|
||||
local
|
||||
s: STRING
|
||||
do
|
||||
s := {HTTP_HEADER_NAMES}.header_set_cookie + colon_space + key + "=" + value
|
||||
if
|
||||
domain /= Void and then not domain.same_string ("localhost")
|
||||
then
|
||||
s.append ("; Domain=")
|
||||
s.append (domain)
|
||||
end
|
||||
if path /= Void then
|
||||
s.append ("; Path=")
|
||||
s.append (path)
|
||||
end
|
||||
if expiration /= Void then
|
||||
s.append ("; Expires=")
|
||||
s.append (expiration)
|
||||
end
|
||||
if secure then
|
||||
s.append ("; Secure")
|
||||
end
|
||||
if http_only then
|
||||
s.append ("; HttpOnly")
|
||||
end
|
||||
add_header (s)
|
||||
end
|
||||
|
||||
put_cookie_with_expiration_date (key, value: READABLE_STRING_8; expiration: DATE_TIME; path, domain: detachable READABLE_STRING_8; secure, http_only: BOOLEAN)
|
||||
-- Set a cookie on the client's machine
|
||||
-- with key 'key' and value 'value'.
|
||||
require
|
||||
make_sense: (key /= Void and value /= Void) and then (not key.is_empty and not value.is_empty)
|
||||
do
|
||||
put_cookie (key, value, date_to_rfc1123_http_date_format (expiration), path, domain, secure, http_only)
|
||||
end
|
||||
|
||||
|
||||
feature -- Access
|
||||
|
||||
date_to_rfc1123_http_date_format (dt: DATE_TIME): STRING_8
|
||||
-- String representation of `dt' using the RFC 1123
|
||||
local
|
||||
d: HTTP_DATE
|
||||
do
|
||||
create d.make_from_date_time (dt)
|
||||
Result := d.string
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
has_same_header_name (h: READABLE_STRING_8; a_name: READABLE_STRING_8): BOOLEAN
|
||||
-- Header line `h' has same name as `a_name' ?
|
||||
do
|
||||
if h.starts_with (a_name) then
|
||||
if h.valid_index (a_name.count + 1) then
|
||||
Result := h[a_name.count + 1] = ':'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Constants
|
||||
|
||||
str_binary: STRING = "binary"
|
||||
str_chunked: STRING = "chunked"
|
||||
|
||||
colon_space: IMMUTABLE_STRING_8
|
||||
once
|
||||
create Result.make_from_string (": ")
|
||||
end
|
||||
|
||||
semi_colon_space: IMMUTABLE_STRING_8
|
||||
once
|
||||
create Result.make_from_string ("; ")
|
||||
end
|
||||
|
||||
comma_space: IMMUTABLE_STRING_8
|
||||
once
|
||||
create Result.make_from_string (", ")
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Jocelyn Fiat, 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
|
||||
@@ -199,17 +199,26 @@ feature -- Cross-Origin Resource Sharing
|
||||
header_access_control_allow_origin: STRING = "Access-Control-Allow-Origin"
|
||||
-- Indicates whether a resource can be shared based by returning
|
||||
-- the value of the Origin request header in the response.
|
||||
-- | Example: Access-Control-Allow-Origin: http://example.org
|
||||
--| Example: Access-Control-Allow-Origin: http://example.org
|
||||
|
||||
header_access_control_allow_credentials: STRING = "Access-Control-Allow-Credentials"
|
||||
-- Indicates whether or not the response to the request can be exposed when the credentials flag is true.
|
||||
-- When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials.
|
||||
-- Note that simple GET requests are not preflighted, and so if a request is made for a resource with credentials,
|
||||
-- if this header is not returned with the resource, the response is ignored by the browser and not returned to web content.
|
||||
--| Access-Control-Allow-Credentials: true | false
|
||||
|
||||
header_access_control_allow_methods: STRING = "Access-Control-Allow-Methods"
|
||||
-- Indicates, as part of the response to a preflight request,
|
||||
-- which methods can be used during the actual request.
|
||||
-- | Example: Access-Control-Allow-Methods: PUT, DELETE
|
||||
--| Access-Control-Allow-Methods: <method>[, <method>]*
|
||||
--| Example: Access-Control-Allow-Methods: PUT, DELETE
|
||||
|
||||
header_access_control_allow_headers: STRING = "Access-Control-Allow-Headers"
|
||||
-- Indicates, as part of the response to a preflight request,
|
||||
-- which header field names can be used during the actual request.
|
||||
-- | Example: Access-Control-Allow-Headers: Authorization
|
||||
--| Access-Control-Allow-Headers: <field-name>[, <field-name>]*
|
||||
--| Example: Access-Control-Allow-Headers: Authorization
|
||||
|
||||
feature -- Request or Response header name
|
||||
|
||||
@@ -265,7 +274,7 @@ feature -- MIME related
|
||||
header_content_transfer_encoding: STRING = "Content-Transfer-Encoding"
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Jocelyn Fiat, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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="notification_email" uuid="99D9A065-CD45-4E20-9C86-579C8AD42E5E" library_target="notification_email">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="notification_email" uuid="99D9A065-CD45-4E20-9C86-579C8AD42E5E" library_target="notification_email">
|
||||
<target name="notification_email">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -13,6 +13,6 @@
|
||||
<library name="http" location="..\..\..\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="process" location="$ISE_LIBRARY\library\process\process-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<cluster name="src" location="." recursive="true"/>
|
||||
<cluster name="src" location=".\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
15
library/runtime/process/notification_email/package.iron
Normal file
15
library/runtime/process/notification_email/package.iron
Normal file
@@ -0,0 +1,15 @@
|
||||
package notification_email
|
||||
|
||||
project
|
||||
notification_email = "notification_email-safe.ecf"
|
||||
notification_email = "notification_email.ecf"
|
||||
|
||||
note
|
||||
-- title:
|
||||
-- description:
|
||||
-- tags:
|
||||
-- license:
|
||||
-- copyright:
|
||||
-- link[doc]: "Documentation" http://
|
||||
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="demo" uuid="DC4D6549-D5F4-4E1A-959A-6BD536737A21" library_target="demo">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="demo" uuid="DC4D6549-D5F4-4E1A-959A-6BD536737A21" library_target="demo">
|
||||
<target name="demo">
|
||||
<root class="APPLICATION" feature="make_and_launch"/>
|
||||
<file_rule>
|
||||
@@ -7,17 +7,17 @@
|
||||
<exclude>/CVS$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<setting name="concurrency" value="thread"/>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi" location="../../../../server/ewsgi/ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi_nino_connector" location="../../../../server/ewsgi/connectors/nino/nino-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="../../../../network/protocol/http/http-safe.ecf"/>
|
||||
<library name="ewsgi" location="..\..\..\..\server\ewsgi\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi_nino_connector" location="..\..\..\..\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\..\..\..\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="openid" location="..\openid-safe.ecf" readonly="false"/>
|
||||
<library name="wsf" location="../../../../server/wsf/wsf-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_nino_connector" location="../../../../server/wsf/connector/nino-safe.ecf" readonly="false"/>
|
||||
<library name="wsf" location="..\..\..\..\server\wsf\wsf-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_nino_connector" location="..\..\..\..\server\wsf\connector\nino-safe.ecf" readonly="false"/>
|
||||
<cluster name="src" location=".\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="openid" uuid="FCDB4F81-31EC-462B-9183-D506E6798C0B" library_target="openid">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="openid" uuid="FCDB4F81-31EC-462B-9183-D506E6798C0B" library_target="openid">
|
||||
<target name="openid">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
|
||||
16
library/security/openid/package.iron
Normal file
16
library/security/openid/package.iron
Normal file
@@ -0,0 +1,16 @@
|
||||
package openid
|
||||
|
||||
project
|
||||
openid = "consumer/openid.ecf"
|
||||
openid = "consumer/openid-safe.ecf"
|
||||
demo = "consumer/demo/demo-safe.ecf"
|
||||
|
||||
note
|
||||
title: Eiffel OpenID
|
||||
description: OpenID library (for now only consumer)
|
||||
tags: openid,security
|
||||
license: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||
-- copyright:
|
||||
-- link[doc]: "Documentation" http://
|
||||
|
||||
end
|
||||
@@ -73,75 +73,163 @@ feature -- Basic operations
|
||||
-- <Precursor>
|
||||
local
|
||||
auth: HTTP_AUTHORIZATION
|
||||
l_authenticated_username: detachable READABLE_STRING_32
|
||||
l_invalid_credential: BOOLEAN
|
||||
do
|
||||
if attached req.http_authorization as l_http_auth then
|
||||
create auth.make (l_http_auth)
|
||||
if attached auth.login as l_login and then is_valid_credential (l_login, auth.password) then
|
||||
handle_authorized (l_login, req, res)
|
||||
l_authenticated_username := auth.login
|
||||
else
|
||||
handle_unauthorized ("ERROR: Invalid credential", req, res)
|
||||
l_invalid_credential := True
|
||||
end
|
||||
end
|
||||
if l_invalid_credential then
|
||||
handle_unauthorized ("ERROR: Invalid credential", req, res)
|
||||
else
|
||||
handle_unauthorized ("ERROR: Authentication information is missing ...", req, res)
|
||||
if l_authenticated_username /= Void then
|
||||
handle_authenticated (l_authenticated_username, req, res)
|
||||
elseif req.path_info.same_string_general ("/login") then
|
||||
handle_unauthorized ("Please provide credential ...", req, res)
|
||||
elseif req.path_info.starts_with_general ("/protected/") then
|
||||
-- any "/protected/*" url
|
||||
handle_unauthorized ("Protected area, please sign in before", req, res)
|
||||
else
|
||||
handle_anonymous (req, res)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
handle_authorized (a_username: READABLE_STRING_32; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
handle_authenticated (a_username: READABLE_STRING_32; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- User `a_username' is authenticated, execute request `req' with response `res'.
|
||||
require
|
||||
valid_username: not a_username.is_empty
|
||||
known_username: is_known_login (a_username)
|
||||
local
|
||||
s: STRING
|
||||
l_logout_url: STRING
|
||||
page: WSF_HTML_PAGE_RESPONSE
|
||||
do
|
||||
create s.make_empty
|
||||
s.append ("Welcome %"")
|
||||
|
||||
append_html_header (req, s)
|
||||
|
||||
s.append ("<p>The authenticated user is <strong>")
|
||||
s.append (html_encoder.general_encoded_string (a_username))
|
||||
s.append ("%" ...<br/>")
|
||||
s.append ("</strong> ...</p>")
|
||||
|
||||
l_logout_url := req.absolute_script_url ("/")
|
||||
l_logout_url.replace_substring_all ("://", "://_@") -- Hack to clear http authorization, i.e connect with bad username.
|
||||
s.append ("<a href=%""+ l_logout_url +"%">logout</a>")
|
||||
append_html_menu (a_username, req, s)
|
||||
append_html_logout (a_username, req, s)
|
||||
append_html_footer (req, s)
|
||||
|
||||
-- Append the raw header data for information
|
||||
if attached req.raw_header_data as l_header then
|
||||
s.append ("<hr/><pre>")
|
||||
s.append (l_header)
|
||||
s.append ("</pre>")
|
||||
end
|
||||
create page.make
|
||||
page.set_body (s)
|
||||
res.send (page)
|
||||
end
|
||||
|
||||
res.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", s.count.out]>>)
|
||||
res.put_string (s)
|
||||
handle_anonymous (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- No user is authenticated, execute request `req' with response `res'.
|
||||
local
|
||||
s: STRING
|
||||
page: WSF_HTML_PAGE_RESPONSE
|
||||
do
|
||||
create s.make_empty
|
||||
append_html_header (req, s)
|
||||
|
||||
s.append ("Anonymous visitor ...<br/>")
|
||||
|
||||
append_html_login (req, s)
|
||||
append_html_menu (Void, req, s)
|
||||
append_html_footer (req, s)
|
||||
|
||||
create page.make
|
||||
page.set_body (s)
|
||||
res.send (page)
|
||||
end
|
||||
|
||||
handle_unauthorized (a_description: STRING; req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
-- Handle forbidden.
|
||||
-- Restricted page, authenticated user is required.
|
||||
-- Send `a_description' as part of the response.
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
s: STRING
|
||||
page: WSF_HTML_PAGE_RESPONSE
|
||||
do
|
||||
create s.make_from_string (a_description)
|
||||
|
||||
-- Append the raw header data for information
|
||||
if attached req.raw_header_data as l_header then
|
||||
s.append ("<hr/><pre>")
|
||||
s.append (l_header)
|
||||
s.append ("</pre>")
|
||||
end
|
||||
append_html_login (req, s)
|
||||
append_html_menu (Void, req, s)
|
||||
append_html_footer (req, s)
|
||||
|
||||
create h.make
|
||||
h.put_content_type_text_html
|
||||
h.put_content_length (s.count)
|
||||
h.put_current_date
|
||||
h.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate,
|
||||
create page.make
|
||||
page.set_status_code ({HTTP_STATUS_CODE}.unauthorized)
|
||||
page.header.put_header_key_value ({HTTP_HEADER_NAMES}.header_www_authenticate,
|
||||
"Basic realm=%"Please enter a valid username and password (demo [" + html_encoder.encoded_string (demo_credential) + "])%""
|
||||
--| warning: for this example: a valid credential is provided in the message, of course that for real application.
|
||||
)
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.unauthorized)
|
||||
res.put_header_text (h.string)
|
||||
res.put_string (s)
|
||||
page.set_body (s)
|
||||
res.send (page)
|
||||
end
|
||||
|
||||
feature -- Helper
|
||||
|
||||
append_html_header (req: WSF_REQUEST; s: STRING)
|
||||
-- Append header paragraph to `s'.
|
||||
do
|
||||
s.append ("<p>The current page is " + html_encoder.encoded_string (req.path_info) + "</p>")
|
||||
end
|
||||
|
||||
append_html_menu (a_username: detachable READABLE_STRING_32; req: WSF_REQUEST; s: STRING)
|
||||
-- Append menu to `s'.
|
||||
-- when an user is authenticated, `a_username' is attached.
|
||||
do
|
||||
if a_username /= Void then
|
||||
s.append ("<li><a href=%""+ req.absolute_script_url ("") +"%">Your account</a> (displayed only is user is authenticated!)</li>")
|
||||
end
|
||||
s.append ("<li><a href=%""+ req.absolute_script_url ("") +"%">home</a></li>")
|
||||
s.append ("<li><a href=%""+ req.script_url ("/public/area") +"%">public area</a></li>")
|
||||
s.append ("<li><a href=%""+ req.script_url ("/protected/area") +"%">protected area</a></li>")
|
||||
end
|
||||
|
||||
append_html_login (req: WSF_REQUEST; s: STRING)
|
||||
-- Append login link to `s'.
|
||||
do
|
||||
s.append ("<li><a href=%""+ req.script_url ("/login") +"%">sign in</a></li>")
|
||||
end
|
||||
|
||||
append_html_logout (a_username: detachable READABLE_STRING_32; req: WSF_REQUEST; s: STRING)
|
||||
-- Append logout link to `s'.
|
||||
local
|
||||
l_logout_url: STRING
|
||||
do
|
||||
l_logout_url := req.absolute_script_url ("/login")
|
||||
l_logout_url.replace_substring_all ("://", "://_@") -- Hack to clear http authorization, i.e connect with bad username "_".
|
||||
s.append ("<li><a href=%""+ l_logout_url +"%">logout</a></li>")
|
||||
end
|
||||
|
||||
append_html_footer (req: WSF_REQUEST; s: STRING)
|
||||
-- Append html footer to `s'.
|
||||
local
|
||||
hauth: HTTP_AUTHORIZATION
|
||||
do
|
||||
s.append ("<hr/>")
|
||||
if attached req.http_authorization as l_http_authorization then
|
||||
s.append ("Has <em>Authorization:</em> header: ")
|
||||
create hauth.make (req.http_authorization)
|
||||
if attached hauth.login as l_login then
|
||||
s.append (" login=<strong>" + html_encoder.encoded_string (l_login)+ "</strong>")
|
||||
end
|
||||
if attached hauth.password as l_password then
|
||||
s.append (" password=<strong>" + html_encoder.encoded_string (l_password)+ "</strong>")
|
||||
end
|
||||
s.append ("<br/>")
|
||||
end
|
||||
if attached req.raw_header_data as l_header then
|
||||
-- Append the raw header data for information
|
||||
s.append ("Raw header data:")
|
||||
s.append ("<pre>")
|
||||
s.append (l_header)
|
||||
s.append ("</pre>")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="http_authorization" uuid="321674DB-CE7C-417C-ADE8-64CFA376CD3E" library_target="http_authorization">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="http_authorization" uuid="321674DB-CE7C-417C-ADE8-64CFA376CD3E" library_target="http_authorization">
|
||||
<target name="http_authorization">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package http_authorization
|
||||
|
||||
project
|
||||
http_authorization = "http_authorization-safe.ecf"
|
||||
http_authorization = "http_authorization.ecf"
|
||||
|
||||
note
|
||||
-- title:
|
||||
-- description:
|
||||
-- tags:
|
||||
-- license:
|
||||
-- copyright:
|
||||
-- link[doc]: "Documentation" http://
|
||||
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="connector_cgi" uuid="3BCBC1C5-9D99-45BB-B15D-B03D2C069CED" library_target="connector_cgi">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="connector_cgi" uuid="3BCBC1C5-9D99-45BB-B15D-B03D2C069CED" library_target="connector_cgi">
|
||||
<target name="connector_cgi">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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="connector_nino" uuid="F91861FB-4FEA-455F-9570-828D7903DC64" library_target="connector_nino">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="connector_nino" uuid="F91861FB-4FEA-455F-9570-828D7903DC64" library_target="connector_nino">
|
||||
<target name="connector_nino">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -7,13 +7,13 @@
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="transitional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="encoder" location="../../../../text/encoder/encoder-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\..\..\text\encoder\encoder-safe.ecf"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="../../../../network/protocol/http/http-safe.ecf"/>
|
||||
<library name="nino" location="../../../../../contrib/library/network/server/nino/nino-safe.ecf" readonly="false">
|
||||
<library name="http" location="..\..\..\..\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="nino" location="..\..\..\..\..\contrib\library\network\server\nino\nino-safe.ecf" readonly="false">
|
||||
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||
</library>
|
||||
<cluster name="src" location=".\src\" recursive="true"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="ewsgi" uuid="D924DBE1-1231-434A-80EF-234BA09D1E30" library_target="ewsgi">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="ewsgi" uuid="D924DBE1-1231-434A-80EF-234BA09D1E30" library_target="ewsgi">
|
||||
<target name="ewsgi">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="ewsgi_spec" uuid="AA193B9F-02FD-47B9-B60D-C42B9AB35E1C" library_target="ewsgi_spec">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="ewsgi_spec" uuid="AA193B9F-02FD-47B9-B60D-C42B9AB35E1C" library_target="ewsgi_spec">
|
||||
<target name="ewsgi_spec">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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="hello_world" uuid="734385F1-0D17-4B5F-9138-24DC8D4F06C6" library_target="hello_world">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="hello_world" uuid="734385F1-0D17-4B5F-9138-24DC8D4F06C6" library_target="hello_world">
|
||||
<target name="hello_world">
|
||||
<root class="HELLO_WORLD" feature="make"/>
|
||||
<file_rule>
|
||||
|
||||
3
library/server/libfcgi/Clib/Makefile-win.SH
Normal file
3
library/server/libfcgi/Clib/Makefile-win.SH
Normal file
@@ -0,0 +1,3 @@
|
||||
all::
|
||||
build_win64.bat
|
||||
|
||||
@@ -16,3 +16,4 @@ link.exe %LINK_FLAGS% /DLL %E_libFCGI_OUTDIR%\fcgi_stdio.obj %E_libFCGI_OUTDIR%
|
||||
copy %E_libFCGI_OUTDIR%\libfcgi.* %~dp0..\spec\lib\windows\msc
|
||||
|
||||
endlocal
|
||||
exit 0
|
||||
|
||||
@@ -16,3 +16,4 @@ link.exe %LINK_FLAGS% /DLL %E_libFCGI_OUTDIR%\fcgi_stdio.obj %E_libFCGI_OUTDIR%
|
||||
copy %E_libFCGI_OUTDIR%\libfcgi.* %~dp0..\spec\lib\win64\msc
|
||||
|
||||
endlocal
|
||||
exit 0
|
||||
|
||||
20
library/server/libfcgi/Clib/build_windows.bat
Normal file
20
library/server/libfcgi/Clib/build_windows.bat
Normal file
@@ -0,0 +1,20 @@
|
||||
setlocal
|
||||
echo off
|
||||
|
||||
if "%ISE_PLATFORM%" == "win64" goto build_win64
|
||||
goto build_win32
|
||||
goto end
|
||||
|
||||
:build_win64
|
||||
echo Building libfcgi for win64
|
||||
%~dp0\build_win64.bat
|
||||
goto end
|
||||
|
||||
:build_win32
|
||||
echo Building libfcgi for win32
|
||||
%~dp0\build_win32.bat
|
||||
goto end
|
||||
|
||||
:end
|
||||
endlocal
|
||||
exit 0
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="libfcgi" uuid="3F4BCF74-3503-4533-9D74-5A65EC4CA3C4" library_target="libfcgi">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="libfcgi" uuid="3F4BCF74-3503-4533-9D74-5A65EC4CA3C4" library_target="libfcgi">
|
||||
<target name="libfcgi">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -46,16 +46,16 @@
|
||||
</file_rule>
|
||||
<file_rule>
|
||||
<exclude>/fake$</exclude>
|
||||
<exclude>/windows$</exclude>
|
||||
<exclude>/mac$</exclude>
|
||||
<exclude>/windows$</exclude>
|
||||
<condition>
|
||||
<platform value="unix"/>
|
||||
</condition>
|
||||
</file_rule>
|
||||
<file_rule>
|
||||
<exclude>/linux$</exclude>
|
||||
<exclude>/fake$</exclude>
|
||||
<exclude>/windows$</exclude>
|
||||
<exclude>/linux$</exclude>
|
||||
<condition>
|
||||
<platform value="macintosh"/>
|
||||
</condition>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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="wsf_all" uuid="223E2E7D-AA90-4ADC-93CB-D304E794E3E6" library_target="wsf_all">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wsf_all" uuid="223E2E7D-AA90-4ADC-93CB-D304E794E3E6" library_target="wsf_all">
|
||||
<target name="wsf_all">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -10,21 +10,20 @@
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<library name="ewsgi" location="../../ewsgi/ewsgi-safe.ecf"/>
|
||||
<library name="wsf" location="../wsf-safe.ecf"/>
|
||||
<library name="connector_cgi" location="../../ewsgi/connectors/cgi/cgi-safe.ecf"/>
|
||||
<library name="connector_libfcgi" location="../../ewsgi/connectors/libfcgi/libfcgi-safe.ecf"/>
|
||||
<library name="connector_nino" location="../../ewsgi/connectors/nino/nino-safe.ecf"/>
|
||||
<library name="connector_cgi" location="..\..\ewsgi\connectors\cgi\cgi-safe.ecf"/>
|
||||
<library name="connector_libfcgi" location="..\..\ewsgi\connectors\libfcgi\libfcgi-safe.ecf"/>
|
||||
<library name="connector_nino" location="..\..\ewsgi\connectors\nino\nino-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\..\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
<library name="error" location="..\..\..\utility\general\error\error-safe.ecf"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi\ewsgi-safe.ecf"/>
|
||||
<library name="http" location="..\..\..\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="nino" location="nino-safe.ecf" readonly="false">
|
||||
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||
</library>
|
||||
|
||||
<library name="error" location="../../../utility/general/error/error-safe.ecf"/>
|
||||
<library name="http" location="../../../network/protocol/http/http-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\..\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
<cluster name="wsf_nino" location="./nino" recursive="true"/>
|
||||
<cluster name="wsf_cgi" location="./cgi" recursive="true"/>
|
||||
<cluster name="wsf_libfcgi" location="./libfcgi" recursive="true"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<library name="wsf" location="..\wsf-safe.ecf"/>
|
||||
<cluster name="wsf_cgi" location=".\cgi\" recursive="true"/>
|
||||
<cluster name="wsf_libfcgi" location=".\libfcgi\" recursive="true"/>
|
||||
<cluster name="wsf_nino" location=".\nino\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="wsf_nino" uuid="BACF0220-900B-4409-8CB2-30A09836A650" library_target="wsf_nino">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wsf_nino" uuid="BACF0220-900B-4409-8CB2-30A09836A650" library_target="wsf_nino">
|
||||
<target name="wsf_nino">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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="wsf_openshift" uuid="39488429-3940-4360-9A32-FE53298C2CA2" library_target="wsf_openshift">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wsf_openshift" uuid="39488429-3940-4360-9A32-FE53298C2CA2" library_target="wsf_openshift">
|
||||
<target name="wsf_openshift">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -10,9 +10,9 @@
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="ewsgi" location="../../ewsgi/ewsgi-safe.ecf"/>
|
||||
<library name="wsf" location="../wsf-safe.ecf"/>
|
||||
<library name="ewsgi" location="..\..\ewsgi\ewsgi-safe.ecf"/>
|
||||
<library name="wsf" location="..\wsf-safe.ecf"/>
|
||||
<library name="wsf_connector_nino" location="nino-safe.ecf"/>
|
||||
<cluster name="wsf_openshift" location="./openshift" recursive="true"/>
|
||||
<cluster name="wsf_openshift" location=".\openshift\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="default_cgi" uuid="A9137009-B5BA-4C58-BCD3-7753909918B5" library_target="default_cgi">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="default_cgi" uuid="A9137009-B5BA-4C58-BCD3-7753909918B5" library_target="default_cgi">
|
||||
<target name="default_cgi">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="default_nino" uuid="ACBEDC97-956C-45F5-97E3-65A6D9987625" library_target="default_nino">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="default_nino" uuid="ACBEDC97-956C-45F5-97E3-65A6D9987625" library_target="default_nino">
|
||||
<target name="default_nino">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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="default_openshift" uuid="9EDB2BD1-9E1B-4931-ADD2-2724E3A25CBF" library_target="default_openshift">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="default_openshift" uuid="9EDB2BD1-9E1B-4931-ADD2-2724E3A25CBF" library_target="default_openshift">
|
||||
<target name="default_openshift">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -7,10 +7,11 @@
|
||||
<exclude>/\.git$</exclude>
|
||||
<exclude>/\.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional"/>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="wsf" location="../wsf-safe.ecf"/>
|
||||
<library name="wsf_openshift" location="../connector/openshift-safe.ecf"/>
|
||||
<cluster name="default_openshift" location="./openshift" recursive="true"/>
|
||||
<library name="wsf" location="..\wsf-safe.ecf"/>
|
||||
<library name="wsf_openshift" location="..\connector\openshift-safe.ecf"/>
|
||||
<cluster name="default_openshift" location=".\openshift\" recursive="true"/>
|
||||
</target>
|
||||
</system>
|
||||
|
||||
@@ -376,10 +376,11 @@ feature -- Error reporting
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
m: READABLE_STRING_8
|
||||
utf: UTF_CONVERTER
|
||||
do
|
||||
m := req.error_handler.as_string_representation
|
||||
m := utf.string_32_to_utf_8_string_8 (req.error_handler.as_string_representation)
|
||||
create h.make
|
||||
h.put_content_type_text_plain
|
||||
h.put_content_type_utf_8_text_plain
|
||||
h.put_content_length (m.count)
|
||||
res.set_status_code (req.error_handler.primary_error_code)
|
||||
res.put_header_lines (h)
|
||||
|
||||
@@ -98,8 +98,8 @@ feature {WSF_RESPONSE} -- Output
|
||||
local
|
||||
h: HTTP_HEADER
|
||||
l_description: STRING_8
|
||||
l_base_url: STRING_8
|
||||
l_api_resource: detachable STRING_8
|
||||
l_base_url: READABLE_STRING_8
|
||||
l_api_resource: detachable READABLE_STRING_8
|
||||
do
|
||||
create h.make
|
||||
h.put_content_type_text_html
|
||||
@@ -132,7 +132,7 @@ feature {WSF_RESPONSE} -- Output
|
||||
if attached router.base_url as u then
|
||||
l_base_url := u
|
||||
else
|
||||
create l_base_url.make_empty
|
||||
create {STRING_8} l_base_url.make_empty
|
||||
end
|
||||
|
||||
debug
|
||||
@@ -324,7 +324,7 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -61,6 +61,7 @@ feature -- Basic operations
|
||||
create h.make_with_count (1)
|
||||
h.put_content_length (s.count)
|
||||
h.put_content_type_text_plain
|
||||
res.set_status_code ({HTTP_STATUS_CODE}.service_unavailable)
|
||||
res.put_header_lines (h)
|
||||
res.put_string (s)
|
||||
else
|
||||
@@ -69,7 +70,7 @@ feature -- Basic operations
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -3,8 +3,8 @@ note
|
||||
Entry of WSF_ROUTER
|
||||
It contains
|
||||
- mapping
|
||||
- request methods
|
||||
|
||||
- request methods
|
||||
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
@@ -40,20 +40,23 @@ feature -- Access
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
debug_output: READABLE_STRING_GENERAL
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
local
|
||||
s: STRING_32
|
||||
do
|
||||
create Result.make_from_string (mapping.debug_output)
|
||||
create s.make_from_string_general (mapping.debug_output)
|
||||
if attached request_methods as mtds then
|
||||
Result.append_string (" [ ")
|
||||
s.append_string (" [ ")
|
||||
across
|
||||
mtds as c
|
||||
loop
|
||||
Result.append_string (c.item)
|
||||
Result.append_string (" ")
|
||||
s.append_string (c.item)
|
||||
s.append_string (" ")
|
||||
end
|
||||
Result.append_string ("]")
|
||||
s.append_string ("]")
|
||||
end
|
||||
Result := s
|
||||
end
|
||||
|
||||
feature -- Change
|
||||
@@ -68,7 +71,7 @@ invariant
|
||||
mapping_attached: mapping /= Void
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -48,10 +48,10 @@ feature -- Documentation
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
debug_output: READABLE_STRING_GENERAL
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
Result := description.as_string_8 + " : " + associated_resource
|
||||
Result := description + {STRING_32} " : " + associated_resource.to_string_32
|
||||
end
|
||||
|
||||
feature -- Status
|
||||
@@ -88,7 +88,7 @@ feature -- Helper
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -45,14 +45,14 @@ feature {NONE} -- Execution
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
debug_output: READABLE_STRING_GENERAL
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
Result := Precursor + " {" + ({C}).name + "}"
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -22,14 +22,14 @@ feature -- Access
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
debug_output: READABLE_STRING_GENERAL
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
Result := Precursor + " {" + ({C}).name + "}"
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -60,15 +60,16 @@ feature {NONE} -- Initialization
|
||||
|
||||
feature -- Cookie
|
||||
|
||||
apply_to (h: HTTP_HEADER; a_request: WSF_REQUEST; a_path: detachable READABLE_STRING_8)
|
||||
apply_to (h: HTTP_HEADER_MODIFIER; a_request: WSF_REQUEST; a_path: detachable READABLE_STRING_8)
|
||||
-- <Precursor>
|
||||
local
|
||||
dt: detachable DATE_TIME
|
||||
l_domain: detachable READABLE_STRING_8
|
||||
do
|
||||
l_domain := a_request.server_name
|
||||
if l_domain.same_string ("localhost") then
|
||||
-- Due to limitation of specific handling of local cookies
|
||||
-- it is recommended to use Void or IP instead of "localhost"
|
||||
-- Due to limitation of specific handling of local cookies
|
||||
-- it is recommended to use Void or IP instead of "localhost"
|
||||
l_domain := Void
|
||||
end
|
||||
if is_destroyed then
|
||||
@@ -79,13 +80,18 @@ feature -- Cookie
|
||||
create dt.make_now_utc
|
||||
dt.day_add (40)
|
||||
end
|
||||
h.put_cookie_with_expiration_date (cookie_name, uuid, dt, a_path, l_domain, False, True)
|
||||
h.put_cookie_with_expiration_date (cookie_name, id, dt, a_path, l_domain, False, True)
|
||||
end
|
||||
end
|
||||
|
||||
cookie_name: READABLE_STRING_8
|
||||
|
||||
feature -- Access
|
||||
feature -- Access
|
||||
|
||||
id: READABLE_STRING_8
|
||||
do
|
||||
Result := uuid
|
||||
end
|
||||
|
||||
uuid: READABLE_STRING_8
|
||||
|
||||
@@ -135,8 +141,8 @@ feature {NONE} -- Storage
|
||||
|
||||
load
|
||||
do
|
||||
if manager.session_exists (uuid) then
|
||||
if attached manager.session_data (uuid) as d then
|
||||
if manager.session_exists (id) then
|
||||
if attached manager.session_data (id) as d then
|
||||
data := d
|
||||
set_expiration (data.expiration)
|
||||
else
|
||||
@@ -177,7 +183,7 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -68,7 +68,7 @@ feature -- Persistence
|
||||
delete_session (a_session)
|
||||
else
|
||||
ensure_session_folder_exists
|
||||
create f.make_with_path (file_name (a_session.uuid))
|
||||
create f.make_with_path (file_name (a_session.id))
|
||||
if not f.exists or else f.is_writable then
|
||||
f.create_read_write
|
||||
a_session.data.set_expiration (a_session.expiration)
|
||||
@@ -91,7 +91,7 @@ feature -- Persistence
|
||||
rescued: BOOLEAN
|
||||
do
|
||||
if not rescued then
|
||||
create f.make_with_path (file_name (a_session.uuid))
|
||||
create f.make_with_path (file_name (a_session.id))
|
||||
if f.exists then
|
||||
f.delete
|
||||
end
|
||||
|
||||
@@ -7,26 +7,43 @@ note
|
||||
deferred class
|
||||
WSF_SESSION
|
||||
|
||||
feature -- Access
|
||||
feature -- Access
|
||||
|
||||
id: READABLE_STRING_8
|
||||
-- Session identifier.
|
||||
deferred
|
||||
end
|
||||
|
||||
uuid: READABLE_STRING_8
|
||||
obsolete
|
||||
"Use `id' which is more general [2014-03]"
|
||||
deferred
|
||||
end
|
||||
|
||||
data: WSF_SESSION_DATA
|
||||
-- Data associated with current session.
|
||||
deferred
|
||||
end
|
||||
|
||||
expiration: detachable DATE_TIME
|
||||
-- Expiration date for current session, if any.
|
||||
deferred
|
||||
end
|
||||
|
||||
expired: BOOLEAN
|
||||
-- Is current session expired now?
|
||||
do
|
||||
Result := expired_at (create {DATE_TIME}.make_now_utc)
|
||||
end
|
||||
|
||||
expired_at (dt: DATE_TIME): BOOLEAN
|
||||
-- Is current session expired at date and time `dt'?
|
||||
do
|
||||
if attached expiration as e then
|
||||
Result := e < (create {DATE_TIME}.make_now_utc)
|
||||
Result := e < (dt)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- status
|
||||
|
||||
is_pending: BOOLEAN
|
||||
@@ -36,27 +53,32 @@ feature -- status
|
||||
end
|
||||
|
||||
is_destroyed: BOOLEAN
|
||||
-- Is current session in destroyed state?
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Entries
|
||||
|
||||
table: TABLE_ITERABLE [detachable ANY, READABLE_STRING_32]
|
||||
table: TABLE_ITERABLE [detachable ANY, READABLE_STRING_GENERAL]
|
||||
-- Table of session data indexed by key
|
||||
do
|
||||
Result := data
|
||||
end
|
||||
|
||||
item (k: READABLE_STRING_GENERAL): detachable ANY
|
||||
item alias "[]" (k: READABLE_STRING_GENERAL): detachable ANY assign remember
|
||||
-- Session value associated with key `k'.
|
||||
do
|
||||
Result := data.item (table_key (k))
|
||||
end
|
||||
|
||||
remember (v: detachable ANY; k: READABLE_STRING_GENERAL)
|
||||
-- Remember value `v' in association with key `k'.
|
||||
do
|
||||
data.force (v, table_key (k))
|
||||
end
|
||||
|
||||
forget (k: READABLE_STRING_GENERAL)
|
||||
-- Forget about value associated with key `k'.
|
||||
do
|
||||
data.remove (table_key (k))
|
||||
end
|
||||
@@ -71,19 +93,30 @@ feature {NONE} -- Implementation
|
||||
feature -- Control
|
||||
|
||||
destroy
|
||||
-- Destroy current session.
|
||||
deferred
|
||||
end
|
||||
|
||||
commit
|
||||
-- Commit current session, including data associated.
|
||||
deferred
|
||||
end
|
||||
|
||||
apply_to (h: HTTP_HEADER; req: WSF_REQUEST; a_path: detachable READABLE_STRING_8)
|
||||
apply_to (h: HTTP_HEADER_MODIFIER; req: WSF_REQUEST; a_path: detachable READABLE_STRING_8)
|
||||
-- Apply current session to header `h' for request `req' and optional path `a_path'.
|
||||
-- note: either use `apply_to' or `apply', not both.
|
||||
deferred
|
||||
end
|
||||
|
||||
apply (req: WSF_REQUEST; res: WSF_RESPONSE; a_path: detachable READABLE_STRING_8)
|
||||
-- Apply current session to response `res' for request `req' and optional path `a_path'.
|
||||
-- note: either use `apply' or `apply_to', not both.
|
||||
do
|
||||
apply_to (res.header, req, a_path)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -8,7 +8,13 @@ class
|
||||
WSF_SESSION_DATA
|
||||
|
||||
inherit
|
||||
HASH_TABLE [detachable ANY, READABLE_STRING_32]
|
||||
STRING_TABLE [detachable ANY]
|
||||
rename
|
||||
make as old_make,
|
||||
make_caseless as make
|
||||
redefine
|
||||
empty_duplicate
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
@@ -24,4 +30,22 @@ feature -- Element change
|
||||
expiration := dt
|
||||
end
|
||||
|
||||
feature {NONE} -- Duplication
|
||||
|
||||
empty_duplicate (n: INTEGER): like Current
|
||||
-- Create an empty copy of Current that can accommodate `n' items
|
||||
do
|
||||
create Result.make (n)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
|
||||
@@ -9,509 +9,11 @@ note
|
||||
class
|
||||
WSF_PERCENT_ENCODER
|
||||
|
||||
feature -- Percent encoding
|
||||
|
||||
percent_encoded_string (v: READABLE_STRING_GENERAL): STRING_8
|
||||
-- Return `a_string' percent-encoded
|
||||
do
|
||||
create Result.make (v.count)
|
||||
append_percent_encoded_string_to (v, Result)
|
||||
end
|
||||
|
||||
append_percent_encoded_string_to (s: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||
-- Append `a_string' as percent-encoded value to `a_result'
|
||||
local
|
||||
c: NATURAL_32
|
||||
i,n: INTEGER
|
||||
do
|
||||
from
|
||||
i := 1
|
||||
n := s.count
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
c := s.code (i)
|
||||
if
|
||||
--| unreserved ALPHA / DIGIT
|
||||
(48 <= c and c <= 57) -- DIGIT: 0 .. 9
|
||||
or (65 <= c and c <= 90) -- ALPHA: A .. Z
|
||||
or (97 <= c and c <= 122) -- ALPHA: a .. z
|
||||
then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
inspect c
|
||||
when
|
||||
45, 46, 95, 126 -- unreserved characters: -._~
|
||||
then
|
||||
a_result.append_code (c)
|
||||
when
|
||||
58, 64, -- reserved =+ gen-delims: :@
|
||||
33, 36, 38, 39, 40, 41, 42, -- reserved =+ sub-delims: !$&'()*
|
||||
43, 44, 59, 61, -- reserved = sub-delims: +,;=
|
||||
37 -- percent encoding: %
|
||||
then
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
else
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Percent encoding: character
|
||||
|
||||
append_percent_encoded_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||
-- Append character code `a_code' as percent-encoded content into `a_result'
|
||||
do
|
||||
if a_code > 0xFF then
|
||||
-- Unicode
|
||||
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||
elseif a_code > 0x7F then
|
||||
-- Extended ASCII
|
||||
-- This requires percent-encoding on UTF-8 converted character.
|
||||
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||
else
|
||||
-- ASCII
|
||||
append_percent_encoded_ascii_character_code_to (a_code, a_result)
|
||||
end
|
||||
ensure
|
||||
appended: a_result.count > old a_result.count
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: character encoding
|
||||
|
||||
append_percent_encoded_ascii_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||
-- Append extended ascii character code `a_code' as percent-encoded content into `a_result'
|
||||
-- Note: it does not UTF-8 convert this extended ASCII.
|
||||
require
|
||||
is_extended_ascii: a_code <= 0xFF
|
||||
local
|
||||
c: INTEGER
|
||||
do
|
||||
if a_code > 0xFF then
|
||||
-- Unicode
|
||||
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||
else
|
||||
-- Extended ASCII
|
||||
c := a_code.to_integer_32
|
||||
a_result.append_code (37) -- 37 '%%'
|
||||
a_result.append_code (hex_digit [c |>> 4])
|
||||
a_result.append_code (hex_digit [c & 0xF])
|
||||
end
|
||||
ensure
|
||||
appended: a_result.count > old a_result.count
|
||||
end
|
||||
|
||||
append_percent_encoded_unicode_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||
-- Append Unicode character code `a_code' as UTF-8 and percent-encoded content into `a_result'
|
||||
-- Note: it does include UTF-8 conversion of extended ASCII and Unicode.
|
||||
do
|
||||
if a_code <= 0x7F then
|
||||
-- 0xxxxxxx
|
||||
append_percent_encoded_ascii_character_code_to (a_code, a_result)
|
||||
elseif a_code <= 0x7FF then
|
||||
-- 110xxxxx 10xxxxxx
|
||||
append_percent_encoded_ascii_character_code_to ((a_code |>> 6) | 0xC0, a_result)
|
||||
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||
elseif a_code <= 0xFFFF then
|
||||
-- 1110xxxx 10xxxxxx 10xxxxxx
|
||||
append_percent_encoded_ascii_character_code_to ((a_code |>> 12) | 0xE0, a_result)
|
||||
append_percent_encoded_ascii_character_code_to (((a_code |>> 6) & 0x3F) | 0x80, a_result)
|
||||
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||
else
|
||||
-- c <= 1FFFFF - there are no higher code points
|
||||
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
append_percent_encoded_ascii_character_code_to ((a_code |>> 18) | 0xF0, a_result)
|
||||
append_percent_encoded_ascii_character_code_to (((a_code |>> 12) & 0x3F) | 0x80, a_result)
|
||||
append_percent_encoded_ascii_character_code_to (((a_code |>> 6) & 0x3F) | 0x80, a_result)
|
||||
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||
end
|
||||
ensure
|
||||
appended: a_result.count > old a_result.count
|
||||
end
|
||||
|
||||
feature -- Percent decoding
|
||||
|
||||
percent_decoded_string (v: READABLE_STRING_GENERAL): STRING_32
|
||||
-- Return the percent decoded string equivalent to the percent-encoded string `v'
|
||||
--| Note that is `a_result' is a STRING_8, any Unicode character will be kept as UTF-8
|
||||
do
|
||||
create Result.make (v.count)
|
||||
append_percent_decoded_string_to (v, Result)
|
||||
end
|
||||
|
||||
append_percent_decoded_string_to (v: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||
-- Append to `a_result' a string equivalent to the percent-encoded string `v'
|
||||
--| Note that is `a_result' is a STRING_8, any Unicode character will be kept as UTF-8
|
||||
local
|
||||
i,n: INTEGER
|
||||
c: NATURAL_32
|
||||
pr: CELL [INTEGER]
|
||||
a_result_is_string_32: BOOLEAN
|
||||
do
|
||||
a_result_is_string_32 := attached {STRING_32} a_result
|
||||
from
|
||||
i := 1
|
||||
create pr.put (i)
|
||||
n := v.count
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
c := v.code (i)
|
||||
inspect c
|
||||
when 43 then -- 43 '+'
|
||||
-- Some implementation are replacing spaces with "+" instead of "%20"
|
||||
a_result.append_code (32) -- 32 ' '
|
||||
when 37 then -- 37 '%%'
|
||||
-- An escaped character ?
|
||||
if i = n then -- Error?
|
||||
a_result.append_code (c)
|
||||
else
|
||||
if a_result_is_string_32 then
|
||||
-- Convert UTF-8 to UTF-32
|
||||
pr.replace (i)
|
||||
c := next_percent_decoded_unicode_character_code (v, pr)
|
||||
a_result.append_code (c)
|
||||
i := pr.item
|
||||
else
|
||||
-- Keep UTF-8
|
||||
pr.replace (i)
|
||||
c := next_percent_decoded_character_code (v, pr)
|
||||
a_result.append_code (c)
|
||||
i := pr.item
|
||||
end
|
||||
end
|
||||
else
|
||||
if c <= 0x7F then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
if a_result_is_string_32 then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
end
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: decoding
|
||||
|
||||
next_percent_decoded_character_code (v: READABLE_STRING_GENERAL; a_position: CELL [INTEGER]): NATURAL_32
|
||||
-- Character decoded from string `v' starting from index `a_position.item'
|
||||
-- note: it also updates `a_position.item' to indicate the new index position.
|
||||
require
|
||||
valid_start: a_position.item <= v.count
|
||||
is_percent_char: v.code (a_position.item) = 37 -- 37 '%%'
|
||||
local
|
||||
c: NATURAL_32
|
||||
i, n: INTEGER
|
||||
not_a_digit: BOOLEAN
|
||||
ascii_pos: NATURAL_32
|
||||
ival: NATURAL_32
|
||||
pos: INTEGER
|
||||
c_is_digit: BOOLEAN
|
||||
do
|
||||
--| pos is index in stream of escape character ('%')
|
||||
pos := a_position.item
|
||||
c := v.code (pos + 1)
|
||||
if c = 85 or c = 117 then -- 117 'u' 85 'U'
|
||||
-- NOTE: this is not a standard, but it can occur, so use this for decoding only
|
||||
-- An escaped Unicode (ucs2) value, from ECMA scripts
|
||||
-- has the form: %u<n> where <n> is the UCS value
|
||||
-- of the character (two byte integer, one to 4 chars
|
||||
-- after escape sequence).
|
||||
-- See: http://en.wikipedia.org/wiki/Percent-encoding#Non-standard_implementations
|
||||
-- UTF-8 result can be 1 to 4 characters.
|
||||
from
|
||||
i := pos + 2
|
||||
n := v.count
|
||||
until
|
||||
(i > n) or not_a_digit
|
||||
loop
|
||||
c := v.code (i)
|
||||
c_is_digit := (48 <= c and c <= 57) -- DIGIT: 0 .. 9
|
||||
if
|
||||
c_is_digit
|
||||
or (97 <= c and c <= 102) -- ALPHA: a..f
|
||||
or (65 <= c and c <= 70) -- ALPHA: A..F
|
||||
then
|
||||
ival := ival * 16
|
||||
if c_is_digit then
|
||||
ival := ival + (c - 48) -- 48 '0'
|
||||
else
|
||||
if c > 70 then -- a..f
|
||||
ival := ival + (c - 97) + 10 -- 97 'a'
|
||||
else -- A..F
|
||||
ival := ival + (c - 65) + 10 -- 65 'A'
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
else
|
||||
not_a_digit := True
|
||||
i := i - 1
|
||||
end
|
||||
end
|
||||
a_position.replace (i)
|
||||
Result := ival
|
||||
else
|
||||
-- ASCII char?
|
||||
ascii_pos := hexadecimal_string_to_natural_32 (v.substring (pos + 1, pos + 2))
|
||||
Result := ascii_pos
|
||||
a_position.replace (pos + 2)
|
||||
end
|
||||
end
|
||||
|
||||
next_percent_decoded_unicode_character_code (v: READABLE_STRING_GENERAL; a_position: CELL [INTEGER]): NATURAL_32
|
||||
-- Next decoded character from `v' at position `a_position.item'
|
||||
-- note: it also updates `a_position' to indicate the new index position.
|
||||
require
|
||||
valid_start: a_position.item <= v.count
|
||||
is_percent_char: v.code (a_position.item) = 37 -- 37 '%%'
|
||||
local
|
||||
n, j: INTEGER
|
||||
c: NATURAL_32
|
||||
c1, c2, c3, c4: NATURAL_32
|
||||
pr: CELL [INTEGER]
|
||||
do
|
||||
create pr.put (a_position.item)
|
||||
c1 := next_percent_decoded_character_code (v, pr)
|
||||
|
||||
j := pr.item
|
||||
n := v.count
|
||||
|
||||
Result := c1
|
||||
a_position.replace (j)
|
||||
|
||||
if c1 <= 0x7F then
|
||||
-- 0xxxxxxx
|
||||
Result := c1
|
||||
elseif c1 <= 0xDF then
|
||||
-- 110xxxxx 10xxxxxx
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c2 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
Result := (
|
||||
((c1 & 0x1F) |<< 6) |
|
||||
( c2 & 0x3F )
|
||||
)
|
||||
a_position.replace (j)
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
elseif c1 <= 0xEF then
|
||||
-- 1110xxxx 10xxxxxx 10xxxxxx
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c2 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c3 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
|
||||
Result := (
|
||||
((c1 & 0xF) |<< 12) |
|
||||
((c2 & 0x3F) |<< 6) |
|
||||
( c3 & 0x3F )
|
||||
)
|
||||
a_position.replace (j)
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
elseif c1 <= 0xF7 then
|
||||
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c2 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c3 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c4 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
|
||||
a_position.replace (j)
|
||||
|
||||
Result := (
|
||||
((c1 & 0x7) |<< 18 ) |
|
||||
((c2 & 0x3F) |<< 12) |
|
||||
((c3 & 0x3F) |<< 6) |
|
||||
( c4 & 0x3F )
|
||||
)
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
Result := c1
|
||||
end
|
||||
end
|
||||
|
||||
feature -- RFC and characters
|
||||
|
||||
is_hexa_decimal_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is hexadecimal character ?
|
||||
do
|
||||
Result := ('a' <= c and c <= 'f') or ('A' <= c and c <= 'F') -- HEXA
|
||||
or ('0' <= c and c <= '9') -- DIGIT
|
||||
end
|
||||
|
||||
is_alpha_or_digit_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is ALPHA or DIGIT character ?
|
||||
do
|
||||
Result := ('a' <= c and c <= 'z') or ('A' <= c and c <= 'Z') -- ALPHA
|
||||
or ('0' <= c and c <= '9') -- DIGIT
|
||||
end
|
||||
|
||||
is_alpha_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is ALPHA character ?
|
||||
do
|
||||
Result := ('a' <= c and c <= 'z') or ('A' <= c and c <= 'Z')
|
||||
end
|
||||
|
||||
is_digit_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is DIGIT character ?
|
||||
do
|
||||
Result := ('0' <= c and c <= '9')
|
||||
end
|
||||
|
||||
is_unreserved_character (c: CHARACTER_32): BOOLEAN
|
||||
-- unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
do
|
||||
if
|
||||
('a' <= c and c <= 'z') -- ALPHA
|
||||
or ('A' <= c and c <= 'Z') -- ALPHA
|
||||
or ('0' <= c and c <= '9') -- DIGIT
|
||||
then
|
||||
Result := True
|
||||
else
|
||||
inspect c
|
||||
when '-', '_', '.', '~' then -- unreserved
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
is_reserved_character (c: CHARACTER_32): BOOLEAN
|
||||
-- reserved = gen-delims / sub-delims
|
||||
do
|
||||
Result := is_gen_delims_character (c) or is_sub_delims_character (c)
|
||||
end
|
||||
|
||||
is_gen_delims_character (c: CHARACTER_32): BOOLEAN
|
||||
-- gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
|
||||
do
|
||||
inspect c
|
||||
when ':' , '/', '?' , '#' , '[' , ']' , '@' then
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
is_sub_delims_character (c: CHARACTER_32): BOOLEAN
|
||||
-- sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
-- / "*" / "+" / "," / ";" / "="
|
||||
do
|
||||
inspect c
|
||||
when '!' , '$' , '&' , '%'' , '(' , ')' , '*' , '+' , ',' , ';' , '=' then -- sub-delims
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
hex_digit: SPECIAL [NATURAL_32]
|
||||
-- Hexadecimal digits.
|
||||
once
|
||||
create Result.make_filled (0, 16)
|
||||
Result [0] := {NATURAL_32} 48 -- 48 '0'
|
||||
Result [1] := {NATURAL_32} 49 -- 49 '1'
|
||||
Result [2] := {NATURAL_32} 50 -- 50 '2'
|
||||
Result [3] := {NATURAL_32} 51 -- 51 '3'
|
||||
Result [4] := {NATURAL_32} 52 -- 52 '4'
|
||||
Result [5] := {NATURAL_32} 53 -- 53 '5'
|
||||
Result [6] := {NATURAL_32} 54 -- 54 '6'
|
||||
Result [7] := {NATURAL_32} 55 -- 55 '7'
|
||||
Result [8] := {NATURAL_32} 56 -- 56 '8'
|
||||
Result [9] := {NATURAL_32} 57 -- 57 '9'
|
||||
Result [10] := {NATURAL_32} 65 -- 65 'A'
|
||||
Result [11] := {NATURAL_32} 66 -- 66 'B'
|
||||
Result [12] := {NATURAL_32} 67 -- 67 'C'
|
||||
Result [13] := {NATURAL_32} 68 -- 68 'D'
|
||||
Result [14] := {NATURAL_32} 69 -- 69 'E'
|
||||
Result [15] := {NATURAL_32} 70 -- 70 'F'
|
||||
end
|
||||
|
||||
is_hexa_decimal (a_string: READABLE_STRING_GENERAL): BOOLEAN
|
||||
-- Is `a_string' a valid hexadecimal sequence?
|
||||
local
|
||||
l_convertor: like ctoi_convertor
|
||||
do
|
||||
l_convertor := ctoi_convertor
|
||||
l_convertor.parse_string_with_type (a_string, {NUMERIC_INFORMATION}.type_natural_32)
|
||||
Result := l_convertor.is_integral_integer
|
||||
end
|
||||
|
||||
hexadecimal_string_to_natural_32 (a_hex_string: READABLE_STRING_GENERAL): NATURAL_32
|
||||
-- Convert hexadecimal value `a_hex_string' to its corresponding NATURAL_32 value.
|
||||
require
|
||||
is_hexa: is_hexa_decimal (a_hex_string)
|
||||
local
|
||||
l_convertor: like ctoi_convertor
|
||||
do
|
||||
l_convertor := ctoi_convertor
|
||||
l_convertor.parse_string_with_type (a_hex_string, {NUMERIC_INFORMATION}.type_no_limitation)
|
||||
Result := l_convertor.parsed_natural_32
|
||||
end
|
||||
|
||||
ctoi_convertor: HEXADECIMAL_STRING_TO_INTEGER_CONVERTER
|
||||
-- Converter used to convert string to integer or natural.
|
||||
once
|
||||
create Result.make
|
||||
Result.set_leading_separators_acceptable (False)
|
||||
Result.set_trailing_separators_acceptable (False)
|
||||
ensure
|
||||
ctoi_convertor_not_void: Result /= Void
|
||||
end
|
||||
inherit
|
||||
PERCENT_ENCODER
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -45,7 +45,7 @@ feature {WSF_RESPONSE} -- Output
|
||||
req := request
|
||||
if attached req.raw_header_data as l_header then
|
||||
create s.make (l_header.count)
|
||||
s.append (l_header.to_string_8)
|
||||
s.append (l_header.to_string_8) -- Is valid as string 8, as ensured by req.raw_header_data
|
||||
s.append_character ('%N')
|
||||
else
|
||||
create s.make_empty
|
||||
@@ -99,7 +99,7 @@ feature {WSF_RESPONSE} -- Output
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -16,6 +16,9 @@ note
|
||||
And also has
|
||||
execution_variable (a_name: READABLE_STRING_GENERAL): detachable ANY
|
||||
--| to keep value attached to the request
|
||||
|
||||
About https support: `is_https' indicates if the request is made through an https connection or not.
|
||||
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
@@ -120,6 +123,20 @@ feature {NONE} -- Initialization
|
||||
if meta_variable ({WSF_META_NAMES}.request_time) = Void then
|
||||
set_meta_string_variable ({WSF_META_NAMES}.request_time, date_time_utilities.unix_time_stamp (Void).out)
|
||||
end
|
||||
|
||||
--| HTTPS support
|
||||
is_https := False
|
||||
if attached meta_string_variable ("HTTPS") as l_https and then not l_https.is_empty then
|
||||
is_https := l_https.is_case_insensitive_equal_general ("on")
|
||||
or else l_https.is_case_insensitive_equal_general ("yes")
|
||||
or else l_https.is_case_insensitive_equal_general ("true")
|
||||
or else l_https.is_case_insensitive_equal_general ("1")
|
||||
--| Usually, if not empty, this means this is https
|
||||
--| but it occurs that server (like IIS) sets "off" when this is NOT https
|
||||
--| so, let's be flexible, and accepts other variants of "on"
|
||||
else
|
||||
check is_not_https: is_https = False end
|
||||
end
|
||||
end
|
||||
|
||||
wgi_request: WGI_REQUEST
|
||||
@@ -156,10 +173,15 @@ feature -- Destroy
|
||||
raw_input_data_recorded := False
|
||||
request_method := empty_string_8
|
||||
set_uploaded_file_path (Void)
|
||||
is_https := False
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_https: BOOLEAN
|
||||
-- Is https connection?
|
||||
--| based on meta variable HTTPS=on .
|
||||
|
||||
debug_output: STRING_8
|
||||
do
|
||||
create Result.make_from_string (request_method + " " + request_uri)
|
||||
@@ -294,25 +316,28 @@ feature -- Access: Input
|
||||
until
|
||||
l_step = 0 or l_input.end_of_input
|
||||
loop
|
||||
l_input.append_to_string (s, l_step)
|
||||
nb := l_input.last_appended_count
|
||||
l_size := l_size + nb.to_natural_64
|
||||
len := len - nb.to_natural_64
|
||||
|
||||
debug ("wsf")
|
||||
io.error.put_string (" append (s, " + l_step.out + ") -> " + nb.out + " (" + l_size.out + " / "+ content_length_value.out + ")%N")
|
||||
end
|
||||
|
||||
a_file.put_string (s)
|
||||
if l_raw_data /= Void then
|
||||
l_raw_data.append (s)
|
||||
end
|
||||
s.wipe_out
|
||||
if nb < l_step then
|
||||
l_step := 0
|
||||
elseif len < l_step.to_natural_64 then
|
||||
if len < l_step.to_natural_64 then
|
||||
l_step := len.to_integer_32
|
||||
end
|
||||
if l_step > 0 then
|
||||
l_input.append_to_string (s, l_step)
|
||||
nb := l_input.last_appended_count
|
||||
l_size := l_size + nb.to_natural_64
|
||||
len := len - nb.to_natural_64
|
||||
|
||||
debug ("wsf")
|
||||
io.error.put_string (" append (s, " + l_step.out + ") -> " + nb.out + " (" + l_size.out + " / "+ content_length_value.out + ")%N")
|
||||
end
|
||||
|
||||
a_file.put_string (s)
|
||||
if l_raw_data /= Void then
|
||||
l_raw_data.append (s)
|
||||
end
|
||||
s.wipe_out
|
||||
if nb < l_step then
|
||||
l_step := 0
|
||||
end
|
||||
end
|
||||
end
|
||||
a_file.flush
|
||||
debug ("wsf")
|
||||
@@ -1262,41 +1287,43 @@ feature {NONE} -- Cookies
|
||||
local
|
||||
i,j,p,n: INTEGER
|
||||
l_cookies: like internal_cookies_table
|
||||
s32: READABLE_STRING_32
|
||||
k,v,s: STRING
|
||||
do
|
||||
l_cookies := internal_cookies_table
|
||||
if l_cookies = Void then
|
||||
create l_cookies.make_equal (0)
|
||||
if attached {WSF_STRING} meta_variable ({WSF_META_NAMES}.http_cookie) as val then
|
||||
s := val.value
|
||||
create l_cookies.make_equal (5)
|
||||
from
|
||||
n := s.count
|
||||
p := 1
|
||||
i := 1
|
||||
until
|
||||
p < 1
|
||||
loop
|
||||
i := s.index_of ('=', p)
|
||||
if i > 0 then
|
||||
j := s.index_of (';', i)
|
||||
if j = 0 then
|
||||
j := n + 1
|
||||
k := s.substring (p, i - 1)
|
||||
v := s.substring (i + 1, n)
|
||||
s32 := val.value
|
||||
if s32.is_valid_as_string_8 then
|
||||
s := s32.to_string_8
|
||||
from
|
||||
n := s.count
|
||||
p := 1
|
||||
i := 1
|
||||
until
|
||||
p < 1
|
||||
loop
|
||||
i := s.index_of ('=', p)
|
||||
if i > 0 then
|
||||
j := s.index_of (';', i)
|
||||
if j = 0 then
|
||||
j := n + 1
|
||||
k := s.substring (p, i - 1)
|
||||
v := s.substring (i + 1, n)
|
||||
|
||||
p := 0 -- force termination
|
||||
else
|
||||
k := s.substring (p, i - 1)
|
||||
v := s.substring (i + 1, j - 1)
|
||||
p := j + 1
|
||||
p := 0 -- force termination
|
||||
else
|
||||
k := s.substring (p, i - 1)
|
||||
v := s.substring (i + 1, j - 1)
|
||||
p := j + 1
|
||||
end
|
||||
k.left_adjust
|
||||
k.right_adjust
|
||||
add_value_to_table (k, v, l_cookies)
|
||||
end
|
||||
k.left_adjust
|
||||
k.right_adjust
|
||||
add_value_to_table (k, v, l_cookies)
|
||||
end
|
||||
end
|
||||
else
|
||||
create l_cookies.make_equal (0)
|
||||
end
|
||||
internal_cookies_table := l_cookies
|
||||
end
|
||||
@@ -1735,10 +1762,7 @@ feature -- URL Utility
|
||||
do
|
||||
s := internal_server_url
|
||||
if s = Void then
|
||||
if
|
||||
server_protocol.count >= 5 and then
|
||||
server_protocol.substring (1, 5).is_case_insensitive_equal ("https")
|
||||
then
|
||||
if is_https then
|
||||
create s.make_from_string ("https://")
|
||||
else
|
||||
create s.make_from_string ("http://")
|
||||
@@ -1746,8 +1770,14 @@ feature -- URL Utility
|
||||
s.append (server_name)
|
||||
p := server_port
|
||||
if p > 0 then
|
||||
s.append_character (':')
|
||||
s.append_integer (p)
|
||||
if is_https and p = 443 then
|
||||
-- :443 is default for https, so no need to put it
|
||||
elseif not is_https and p = 80 then
|
||||
-- :80 is default for http, so no need to put it
|
||||
else
|
||||
s.append_character (':')
|
||||
s.append_integer (p)
|
||||
end
|
||||
end
|
||||
end
|
||||
Result := s
|
||||
@@ -2065,7 +2095,7 @@ invariant
|
||||
wgi_request.content_type /= Void implies content_type /= Void
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -35,7 +35,7 @@ feature {NONE} -- Initialization
|
||||
wres: detachable WSF_WGI_DELAYED_HEADER_RESPONSE
|
||||
do
|
||||
transfered_content_length := 0
|
||||
create header.make
|
||||
create internal_header.make
|
||||
wgi_response := r
|
||||
if attached {WSF_WGI_DELAYED_HEADER_RESPONSE} r as r_delayed then
|
||||
r_delayed.update_wsf_response (Current)
|
||||
@@ -53,7 +53,7 @@ feature {NONE} -- Initialization
|
||||
do
|
||||
transfered_content_length := 0
|
||||
wgi_response := res.wgi_response
|
||||
header := res.header
|
||||
internal_header := res.internal_header
|
||||
set_status_code ({HTTP_STATUS_CODE}.ok) -- Default value
|
||||
end
|
||||
|
||||
@@ -62,7 +62,7 @@ feature {WSF_RESPONSE, WSF_RESPONSE_EXPORTER} -- Properties
|
||||
wgi_response: WGI_RESPONSE
|
||||
-- Associated WGI_RESPONSE.
|
||||
|
||||
header: WSF_HEADER
|
||||
internal_header: WSF_HEADER
|
||||
-- Associated response header.
|
||||
|
||||
feature {WSF_RESPONSE_EXPORTER} -- Change
|
||||
@@ -158,7 +158,7 @@ feature {WSF_RESPONSE_EXPORTER} -- Header output operation
|
||||
-- commit status code and reason phrase
|
||||
wgi_response.set_status_code (status_code, status_reason_phrase)
|
||||
-- commit header text
|
||||
wgi_response.put_header_text (header.string)
|
||||
wgi_response.put_header_text (internal_header.string)
|
||||
end
|
||||
ensure
|
||||
status_committed: status_committed
|
||||
@@ -170,6 +170,26 @@ feature {WSF_RESPONSE_EXPORTER} -- Header output operation
|
||||
put_error ("Content already sent, new header text ignored!")
|
||||
end
|
||||
|
||||
feature -- Header access
|
||||
|
||||
header: HTTP_HEADER_MODIFIER
|
||||
-- Associated header builder interface.
|
||||
local
|
||||
res: like internal_response_header
|
||||
do
|
||||
res := internal_response_header
|
||||
if res = Void then
|
||||
create {WSF_RESPONSE_HEADER} res.make_with_response (Current)
|
||||
internal_response_header := res
|
||||
end
|
||||
Result := res
|
||||
end
|
||||
|
||||
feature {NONE} -- Header access
|
||||
|
||||
internal_response_header: detachable like header
|
||||
-- Cached version of `header'.
|
||||
|
||||
feature -- Header output operation
|
||||
|
||||
put_header_line (h: READABLE_STRING_8)
|
||||
@@ -181,7 +201,7 @@ feature -- Header output operation
|
||||
if header_committed then
|
||||
report_content_already_sent_and_header_ignored
|
||||
else
|
||||
header.put_header (h)
|
||||
internal_header.put_header (h)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -194,7 +214,7 @@ feature -- Header output operation
|
||||
if header_committed then
|
||||
report_content_already_sent_and_header_ignored
|
||||
else
|
||||
header.add_header (h)
|
||||
internal_header.add_header (h)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -209,7 +229,7 @@ feature -- Header output operation
|
||||
if header_committed then
|
||||
report_content_already_sent_and_header_ignored
|
||||
else
|
||||
header.put_raw_header_data (a_text)
|
||||
internal_header.put_raw_header_data (a_text)
|
||||
end
|
||||
ensure
|
||||
message_writable: message_writable
|
||||
@@ -227,7 +247,7 @@ feature -- Header output operation
|
||||
if header_committed then
|
||||
report_content_already_sent_and_header_ignored
|
||||
else
|
||||
header.append_raw_header_data (a_text)
|
||||
internal_header.append_raw_header_data (a_text)
|
||||
end
|
||||
ensure
|
||||
status_set: status_is_set
|
||||
@@ -496,7 +516,7 @@ feature -- Error reporting
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
64
library/server/wsf/src/wsf_response_header.e
Normal file
64
library/server/wsf/src/wsf_response_header.e
Normal file
@@ -0,0 +1,64 @@
|
||||
note
|
||||
description: "[
|
||||
Interface to build the http header associated with WSF_RESPONSE.
|
||||
]"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
WSF_RESPONSE_HEADER
|
||||
|
||||
inherit
|
||||
HTTP_HEADER_MODIFIER
|
||||
|
||||
WSF_RESPONSE_EXPORTER -- to access WSF_RESPONSE.internal_header
|
||||
|
||||
create
|
||||
make_with_response
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_with_response (res: WSF_RESPONSE)
|
||||
do
|
||||
response := res
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
response: WSF_RESPONSE
|
||||
|
||||
feature -- Access
|
||||
|
||||
new_cursor: INDEXABLE_ITERATION_CURSOR [READABLE_STRING_8]
|
||||
-- Fresh cursor associated with current structure.
|
||||
do
|
||||
Result := response.internal_header.new_cursor
|
||||
end
|
||||
|
||||
feature -- Header change: core
|
||||
|
||||
add_header (h: READABLE_STRING_8)
|
||||
-- Add header `h'
|
||||
-- if it already exists, there will be multiple header with same name
|
||||
-- which can also be valid
|
||||
do
|
||||
response.add_header_line (h)
|
||||
end
|
||||
|
||||
put_header (h: READABLE_STRING_8)
|
||||
-- Add header `h' or replace existing header of same header name
|
||||
do
|
||||
response.put_header_line (h)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2014, Jocelyn Fiat, Javier Velilla, Olivier Ligot, Colin Adams, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf" uuid="A37CE5AA-4D2A-4441-BC6A-0A1D7EC49647" library_target="wsf">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wsf" uuid="A37CE5AA-4D2A-4441-BC6A-0A1D7EC49647" library_target="wsf">
|
||||
<target name="wsf">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -11,11 +11,11 @@
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="base_extension" location="$ISE_LIBRARY\library\base_extension\base_extension-safe.ecf"/>
|
||||
<library name="conneg" location="..\..\network\protocol\content_negotiation\conneg-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\text\encoder\encoder-safe.ecf"/>
|
||||
<library name="error" location="..\..\utility\general\error\error-safe.ecf"/>
|
||||
<library name="ewsgi" location="..\ewsgi\ewsgi-safe.ecf"/>
|
||||
<library name="http" location="..\..\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="conneg" location="..\..\network\protocol\content_negotiation\conneg-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
|
||||
<library name="uri_template" location="..\..\text\parser\uri_template\uri_template-safe.ecf"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="wsf_policy_driven" uuid="3FC00449-5101-461D-94C6-10920C30EBF4" library_target="wsf_policy_driven">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="wsf_policy_driven" uuid="3FC00449-5101-461D-94C6-10920C30EBF4" library_target="wsf_policy_driven">
|
||||
<target name="wsf_policy_driven">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
@@ -10,12 +10,12 @@
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard">
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<library name="conneg" location="..\..\network\protocol\content_negotiation\conneg-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\text\encoder\encoder-safe.ecf"/>
|
||||
<library name="ewsgi" location="..\ewsgi\ewsgi-safe.ecf"/>
|
||||
<library name="http" location="..\..\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||
<library name="uri" location="$ISE_LIBRARY\library\text\uri\uri-safe.ecf"/>
|
||||
<library name="ewsgi" location="..\ewsgi\ewsgi-safe.ecf"/>
|
||||
<library name="conneg" location="../../network/protocol/content_negotiation/conneg-safe.ecf"/>
|
||||
<library name="encoder" location="..\..\text\encoder\encoder-safe.ecf"/>
|
||||
<library name="http" location="..\..\network\protocol\http\http-safe.ecf"/>
|
||||
<library name="wsf" location="wsf-safe.ecf"/>
|
||||
<cluster name="policy" location=".\policy_driven\" recursive="true"/>
|
||||
</target>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-11-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-11-0 http://www.eiffel.com/developers/xml/configuration-1-11-0.xsd" name="encoder" uuid="EE80E648-C64D-4802-8868-C57AAFEACC55" library_target="encoder">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="encoder" uuid="EE80E648-C64D-4802-8868-C57AAFEACC55" library_target="encoder">
|
||||
<target name="encoder">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
${NOTE_KEYWORD}
|
||||
copyright: "2011-${YEAR}, Eiffel Software and others"
|
||||
copyright: "Copyright (c) 2011-${YEAR}, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -125,17 +125,17 @@ feature -- Decoder
|
||||
byte_count := 0
|
||||
|
||||
pos := next_encoded_character_position (v, pos)
|
||||
if pos <= n then
|
||||
if pos < n then
|
||||
byte1 := base64chars.index_of (v[pos], 1) - 1
|
||||
byte_count := byte_count + 1
|
||||
|
||||
pos := next_encoded_character_position (v, pos)
|
||||
if pos <= n then
|
||||
if pos < n then
|
||||
byte2 := base64chars.index_of (v[pos], 1) - 1
|
||||
byte_count := byte_count + 1
|
||||
|
||||
pos := next_encoded_character_position (v, pos)
|
||||
if pos <= n then
|
||||
if pos < n then
|
||||
c := v[pos]
|
||||
if c /= '=' then
|
||||
byte3 := base64chars.index_of (c, 1) - 1
|
||||
@@ -150,8 +150,14 @@ feature -- Decoder
|
||||
byte_count := byte_count + 1
|
||||
end
|
||||
end
|
||||
else
|
||||
has_error := True
|
||||
end
|
||||
else
|
||||
has_error := True
|
||||
end
|
||||
else
|
||||
has_error := True
|
||||
end
|
||||
-- pos := pos + byte_count
|
||||
|
||||
@@ -293,7 +299,7 @@ feature {NONE} -- Constants
|
||||
character_map: STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
copyright: "Copyright (c) 2011-2014, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -50,8 +50,11 @@ feature -- Encoder
|
||||
inspect c
|
||||
when '%"' then Result.append_string ("\%"")
|
||||
when '\' then Result.append_string ("\\")
|
||||
when '%R' then Result.append_string ("\r")
|
||||
when '%B' then Result.append_string ("\b")
|
||||
when '%F' then Result.append_string ("\f")
|
||||
when '%N' then Result.append_string ("\n")
|
||||
when '%R' then Result.append_string ("\r")
|
||||
when '%T' then Result.append_string ("\t")
|
||||
else
|
||||
Result.extend (c)
|
||||
end
|
||||
@@ -103,12 +106,21 @@ feature -- Decoder
|
||||
when '%"' then
|
||||
Result.append_character ('%"')
|
||||
i := i + 2
|
||||
when 'b' then
|
||||
Result.append_character ('%B')
|
||||
i := i + 2
|
||||
when 'f' then
|
||||
Result.append_character ('%F')
|
||||
i := i + 2
|
||||
when 'n' then
|
||||
Result.append_character ('%N')
|
||||
i := i + 2
|
||||
when 'r' then
|
||||
Result.append_character ('%R')
|
||||
i := i + 2
|
||||
when 't' then
|
||||
Result.append_character ('%T')
|
||||
i := i + 2
|
||||
when 'u' then
|
||||
hex := v.substring (i+2, i+2+4 - 1)
|
||||
if hex.count = 4 then
|
||||
@@ -170,7 +182,7 @@ feature {NONE} -- Implementation
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Eiffel Software and others"
|
||||
copyright: "Copyright (c) 2011-2014, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
599
library/text/encoder/src/percent_encoder.e
Normal file
599
library/text/encoder/src/percent_encoder.e
Normal file
@@ -0,0 +1,599 @@
|
||||
note
|
||||
description: "[
|
||||
Component to handle percent encoding
|
||||
]"
|
||||
date: "$Date: 2014-04-09 16:37:28 +0200 (mer., 09 avr. 2014) $"
|
||||
revision: "$Revision: 94801 $"
|
||||
EIS: "name=Percent-encoding", "protocol=URI", "src=http://en.wikipedia.org/wiki/Percent-encoding"
|
||||
|
||||
class
|
||||
PERCENT_ENCODER
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has_error: BOOLEAN
|
||||
-- Error occurred
|
||||
--| For now this is not fully implemented, and thus not reliable.
|
||||
|
||||
feature -- Percent encoding
|
||||
|
||||
percent_encoded_string (s: READABLE_STRING_GENERAL): STRING_8
|
||||
-- Return `s' percent-encoded
|
||||
do
|
||||
create Result.make (s.count)
|
||||
append_percent_encoded_string_to (s, Result)
|
||||
end
|
||||
|
||||
append_percent_encoded_string_to (s: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||
-- Append `s' as percent-encoded value to `a_result'
|
||||
local
|
||||
c: NATURAL_32
|
||||
i,n: INTEGER
|
||||
do
|
||||
has_error := False
|
||||
from
|
||||
i := 1
|
||||
n := s.count
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
c := s.code (i)
|
||||
if
|
||||
--| unreserved ALPHA / DIGIT
|
||||
(48 <= c and c <= 57) -- DIGIT: 0 .. 9
|
||||
or (65 <= c and c <= 90) -- ALPHA: A .. Z
|
||||
or (97 <= c and c <= 122) -- ALPHA: a .. z
|
||||
then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
inspect c
|
||||
when
|
||||
45, 46, 95, 126 -- unreserved characters: -._~
|
||||
then
|
||||
a_result.append_code (c)
|
||||
when
|
||||
58, 64, -- reserved =+ gen-delims: :@
|
||||
33, 36, 38, 39, 40, 41, 42, -- reserved =+ sub-delims: !$&'()*
|
||||
43, 44, 59, 61, -- reserved = sub-delims: +,;=
|
||||
37 -- percent encoding: %
|
||||
then
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
else
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
partial_encoded_string (s: READABLE_STRING_GENERAL; a_ignore: ITERABLE [CHARACTER]): STRING_8
|
||||
-- Return `s' as percent-encoded value,
|
||||
-- but does not escape character listed in `a_ignore'.
|
||||
do
|
||||
create Result.make (s.count)
|
||||
append_partial_percent_encoded_string_to (s, Result, a_ignore)
|
||||
end
|
||||
|
||||
append_partial_percent_encoded_string_to (s: READABLE_STRING_GENERAL; a_result: STRING_GENERAL; a_ignore: ITERABLE [CHARACTER])
|
||||
-- Append `s' as percent-encoded value to `a_result',
|
||||
-- but does not escape character listed in `a_ignore'.
|
||||
local
|
||||
c: NATURAL_32
|
||||
ch: CHARACTER_8
|
||||
i,n: INTEGER
|
||||
do
|
||||
has_error := False
|
||||
from
|
||||
i := 1
|
||||
n := s.count
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
c := s.code (i)
|
||||
if
|
||||
--| unreserved ALPHA / DIGIT
|
||||
(48 <= c and c <= 57) -- DIGIT: 0 .. 9
|
||||
or (65 <= c and c <= 90) -- ALPHA: A .. Z
|
||||
or (97 <= c and c <= 122) -- ALPHA: a .. z
|
||||
then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
inspect c
|
||||
when
|
||||
45, 46, 95, 126 -- unreserved characters: -._~
|
||||
then
|
||||
a_result.append_code (c)
|
||||
when
|
||||
58, 64, -- reserved =+ gen-delims: :@
|
||||
33, 36, 38, 39, 40, 41, 42, -- reserved =+ sub-delims: !$&'()*
|
||||
43, 44, 59, 61, -- reserved = sub-delims: +,;=
|
||||
37 -- percent encoding: %
|
||||
then
|
||||
check c.is_valid_character_8_code end
|
||||
ch := c.to_character_8
|
||||
if across a_ignore as ic some ic.item = ch end then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
end
|
||||
else
|
||||
if c.is_valid_character_8_code then
|
||||
ch := c.to_character_8
|
||||
if across a_ignore as ic some ic.item = ch end then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
end
|
||||
else
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
end
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Percent encoding: character
|
||||
|
||||
append_percent_encoded_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||
-- Append character code `a_code' as percent-encoded content into `a_result'
|
||||
do
|
||||
if a_code > 0xFF then
|
||||
-- Unicode
|
||||
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||
elseif a_code > 0x7F then
|
||||
-- Extended ASCII
|
||||
-- This requires percent-encoding on UTF-8 converted character.
|
||||
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||
else
|
||||
-- ASCII
|
||||
append_percent_encoded_ascii_character_code_to (a_code, a_result)
|
||||
end
|
||||
ensure
|
||||
appended: a_result.count > old a_result.count
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: character encoding
|
||||
|
||||
append_percent_encoded_ascii_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||
-- Append extended ascii character code `a_code' as percent-encoded content into `a_result'
|
||||
-- Note: it does not UTF-8 convert this extended ASCII.
|
||||
require
|
||||
is_extended_ascii: a_code <= 0xFF
|
||||
local
|
||||
c: INTEGER
|
||||
do
|
||||
if a_code > 0xFF then
|
||||
-- Unicode
|
||||
append_percent_encoded_unicode_character_code_to (a_code, a_result)
|
||||
else
|
||||
-- Extended ASCII
|
||||
c := a_code.to_integer_32
|
||||
a_result.append_code (37) -- 37 '%%'
|
||||
a_result.append_code (hex_digit [c |>> 4])
|
||||
a_result.append_code (hex_digit [c & 0xF])
|
||||
end
|
||||
ensure
|
||||
appended: a_result.count > old a_result.count
|
||||
end
|
||||
|
||||
append_percent_encoded_unicode_character_code_to (a_code: NATURAL_32; a_result: STRING_GENERAL)
|
||||
-- Append Unicode character code `a_code' as UTF-8 and percent-encoded content into `a_result'
|
||||
-- Note: it does include UTF-8 conversion of extended ASCII and Unicode.
|
||||
do
|
||||
if a_code <= 0x7F then
|
||||
-- 0xxxxxxx
|
||||
append_percent_encoded_ascii_character_code_to (a_code, a_result)
|
||||
elseif a_code <= 0x7FF then
|
||||
-- 110xxxxx 10xxxxxx
|
||||
append_percent_encoded_ascii_character_code_to ((a_code |>> 6) | 0xC0, a_result)
|
||||
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||
elseif a_code <= 0xFFFF then
|
||||
-- 1110xxxx 10xxxxxx 10xxxxxx
|
||||
append_percent_encoded_ascii_character_code_to ((a_code |>> 12) | 0xE0, a_result)
|
||||
append_percent_encoded_ascii_character_code_to (((a_code |>> 6) & 0x3F) | 0x80, a_result)
|
||||
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||
else
|
||||
-- c <= 1FFFFF - there are no higher code points
|
||||
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
append_percent_encoded_ascii_character_code_to ((a_code |>> 18) | 0xF0, a_result)
|
||||
append_percent_encoded_ascii_character_code_to (((a_code |>> 12) & 0x3F) | 0x80, a_result)
|
||||
append_percent_encoded_ascii_character_code_to (((a_code |>> 6) & 0x3F) | 0x80, a_result)
|
||||
append_percent_encoded_ascii_character_code_to ((a_code & 0x3F) | 0x80, a_result)
|
||||
end
|
||||
ensure
|
||||
appended: a_result.count > old a_result.count
|
||||
end
|
||||
|
||||
feature -- Percent decoding
|
||||
|
||||
percent_decoded_string (v: READABLE_STRING_GENERAL): STRING_32
|
||||
-- Return the percent decoded string equivalent to the percent-encoded string `v'
|
||||
--| Note that is `a_result' is a STRING_8, any Unicode character will be kept as UTF-8
|
||||
do
|
||||
create Result.make (v.count)
|
||||
append_percent_decoded_string_to (v, Result)
|
||||
end
|
||||
|
||||
append_percent_decoded_string_to (v: READABLE_STRING_GENERAL; a_result: STRING_GENERAL)
|
||||
-- Append to `a_result' a string equivalent to the percent-encoded string `v'
|
||||
--| Note that is `a_result' is a STRING_8, any Unicode character will be kept as UTF-8
|
||||
local
|
||||
i,n: INTEGER
|
||||
c: NATURAL_32
|
||||
pr: CELL [INTEGER]
|
||||
a_result_is_string_32: BOOLEAN
|
||||
do
|
||||
has_error := False
|
||||
a_result_is_string_32 := attached {STRING_32} a_result
|
||||
from
|
||||
i := 1
|
||||
create pr.put (i)
|
||||
n := v.count
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
c := v.code (i)
|
||||
inspect c
|
||||
when 43 then -- 43 '+'
|
||||
-- Some implementation are replacing spaces with "+" instead of "%20"
|
||||
a_result.append_code (32) -- 32 ' '
|
||||
when 37 then -- 37 '%%'
|
||||
-- An escaped character ?
|
||||
if i = n then -- Error?
|
||||
has_error := True
|
||||
a_result.append_code (c)
|
||||
else
|
||||
if a_result_is_string_32 then
|
||||
-- Convert UTF-8 to UTF-32
|
||||
pr.replace (i)
|
||||
c := next_percent_decoded_unicode_character_code (v, pr)
|
||||
a_result.append_code (c)
|
||||
i := pr.item
|
||||
else
|
||||
-- Keep UTF-8
|
||||
pr.replace (i)
|
||||
c := next_percent_decoded_character_code (v, pr)
|
||||
a_result.append_code (c)
|
||||
i := pr.item
|
||||
end
|
||||
end
|
||||
else
|
||||
if c <= 0x7F then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
if a_result_is_string_32 then
|
||||
a_result.append_code (c)
|
||||
else
|
||||
append_percent_encoded_character_code_to (c, a_result)
|
||||
end
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: decoding
|
||||
|
||||
next_percent_decoded_character_code (v: READABLE_STRING_GENERAL; a_position: CELL [INTEGER]): NATURAL_32
|
||||
-- Character decoded from string `v' starting from index `a_position.item'
|
||||
-- note: it also updates `a_position.item' to indicate the new index position.
|
||||
require
|
||||
valid_start: a_position.item <= v.count
|
||||
is_percent_char: v.code (a_position.item) = 37 -- 37 '%%'
|
||||
local
|
||||
c: NATURAL_32
|
||||
i, n: INTEGER
|
||||
not_a_digit: BOOLEAN
|
||||
ascii_pos: NATURAL_32
|
||||
ival: NATURAL_32
|
||||
pos: INTEGER
|
||||
c_is_digit: BOOLEAN
|
||||
do
|
||||
--| pos is index in stream of escape character ('%')
|
||||
pos := a_position.item
|
||||
c := v.code (pos + 1)
|
||||
if c = 85 or c = 117 then -- 117 'u' 85 'U'
|
||||
-- NOTE: this is not a standard, but it can occur, so use this for decoding only
|
||||
-- An escaped Unicode (ucs2) value, from ECMA scripts
|
||||
-- has the form: %u<n> where <n> is the UCS value
|
||||
-- of the character (two byte integer, one to 4 chars
|
||||
-- after escape sequence).
|
||||
-- See: http://en.wikipedia.org/wiki/Percent-encoding#Non-standard_implementations
|
||||
-- UTF-8 result can be 1 to 4 characters.
|
||||
from
|
||||
i := pos + 2
|
||||
n := v.count
|
||||
until
|
||||
(i > n) or not_a_digit
|
||||
loop
|
||||
c := v.code (i)
|
||||
c_is_digit := (48 <= c and c <= 57) -- DIGIT: 0 .. 9
|
||||
if
|
||||
c_is_digit
|
||||
or (97 <= c and c <= 102) -- ALPHA: a..f
|
||||
or (65 <= c and c <= 70) -- ALPHA: A..F
|
||||
then
|
||||
ival := ival * 16
|
||||
if c_is_digit then
|
||||
ival := ival + (c - 48) -- 48 '0'
|
||||
else
|
||||
if c > 70 then -- a..f
|
||||
ival := ival + (c - 97) + 10 -- 97 'a'
|
||||
else -- A..F
|
||||
ival := ival + (c - 65) + 10 -- 65 'A'
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
else
|
||||
not_a_digit := True
|
||||
i := i - 1
|
||||
end
|
||||
end
|
||||
a_position.replace (i)
|
||||
Result := ival
|
||||
else
|
||||
-- ASCII char?
|
||||
ascii_pos := hexadecimal_string_to_natural_32 (v.substring (pos + 1, pos + 2))
|
||||
Result := ascii_pos
|
||||
a_position.replace (pos + 2)
|
||||
end
|
||||
end
|
||||
|
||||
next_percent_decoded_unicode_character_code (v: READABLE_STRING_GENERAL; a_position: CELL [INTEGER]): NATURAL_32
|
||||
-- Next decoded character from `v' at position `a_position.item'
|
||||
-- note: it also updates `a_position' to indicate the new index position.
|
||||
require
|
||||
valid_start: a_position.item <= v.count
|
||||
is_percent_char: v.code (a_position.item) = 37 -- 37 '%%'
|
||||
local
|
||||
n, j: INTEGER
|
||||
c: NATURAL_32
|
||||
c1, c2, c3, c4: NATURAL_32
|
||||
pr: CELL [INTEGER]
|
||||
do
|
||||
create pr.put (a_position.item)
|
||||
c1 := next_percent_decoded_character_code (v, pr)
|
||||
|
||||
j := pr.item
|
||||
n := v.count
|
||||
|
||||
Result := c1
|
||||
a_position.replace (j)
|
||||
|
||||
if c1 <= 0x7F then
|
||||
-- 0xxxxxxx
|
||||
Result := c1
|
||||
elseif c1 <= 0xDF then
|
||||
-- 110xxxxx 10xxxxxx
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c2 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
Result := (
|
||||
((c1 & 0x1F) |<< 6) |
|
||||
( c2 & 0x3F )
|
||||
)
|
||||
a_position.replace (j)
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
elseif c1 <= 0xEF then
|
||||
-- 1110xxxx 10xxxxxx 10xxxxxx
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c2 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c3 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
|
||||
Result := (
|
||||
((c1 & 0xF) |<< 12) |
|
||||
((c2 & 0x3F) |<< 6) |
|
||||
( c3 & 0x3F )
|
||||
)
|
||||
a_position.replace (j)
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
elseif c1 <= 0xF7 then
|
||||
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c2 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c3 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
if j + 2 <= n then
|
||||
c := v.code (j + 1)
|
||||
if c = 37 then -- 37 '%%'
|
||||
pr.replace (j + 1)
|
||||
c4 := next_percent_decoded_character_code (v, pr)
|
||||
j := pr.item
|
||||
|
||||
a_position.replace (j)
|
||||
|
||||
Result := (
|
||||
((c1 & 0x7) |<< 18 ) |
|
||||
((c2 & 0x3F) |<< 12) |
|
||||
((c3 & 0x3F) |<< 6) |
|
||||
( c4 & 0x3F )
|
||||
)
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Do not try to decode
|
||||
end
|
||||
end
|
||||
else
|
||||
Result := c1
|
||||
end
|
||||
end
|
||||
|
||||
feature -- RFC and characters
|
||||
|
||||
is_hexa_decimal_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is hexadecimal character ?
|
||||
do
|
||||
Result := ('a' <= c and c <= 'f') or ('A' <= c and c <= 'F') -- HEXA
|
||||
or ('0' <= c and c <= '9') -- DIGIT
|
||||
end
|
||||
|
||||
is_alpha_or_digit_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is ALPHA or DIGIT character ?
|
||||
do
|
||||
Result := ('a' <= c and c <= 'z') or ('A' <= c and c <= 'Z') -- ALPHA
|
||||
or ('0' <= c and c <= '9') -- DIGIT
|
||||
end
|
||||
|
||||
is_alpha_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is ALPHA character ?
|
||||
do
|
||||
Result := ('a' <= c and c <= 'z') or ('A' <= c and c <= 'Z')
|
||||
end
|
||||
|
||||
is_digit_character (c: CHARACTER_32): BOOLEAN
|
||||
-- Is DIGIT character ?
|
||||
do
|
||||
Result := ('0' <= c and c <= '9')
|
||||
end
|
||||
|
||||
is_unreserved_character (c: CHARACTER_32): BOOLEAN
|
||||
-- unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
do
|
||||
if
|
||||
('a' <= c and c <= 'z') -- ALPHA
|
||||
or ('A' <= c and c <= 'Z') -- ALPHA
|
||||
or ('0' <= c and c <= '9') -- DIGIT
|
||||
then
|
||||
Result := True
|
||||
else
|
||||
inspect c
|
||||
when '-', '_', '.', '~' then -- unreserved
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
is_reserved_character (c: CHARACTER_32): BOOLEAN
|
||||
-- reserved = gen-delims / sub-delims
|
||||
do
|
||||
Result := is_gen_delims_character (c) or is_sub_delims_character (c)
|
||||
end
|
||||
|
||||
is_gen_delims_character (c: CHARACTER_32): BOOLEAN
|
||||
-- gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
|
||||
do
|
||||
inspect c
|
||||
when ':' , '/', '?' , '#' , '[' , ']' , '@' then
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
is_sub_delims_character (c: CHARACTER_32): BOOLEAN
|
||||
-- sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
-- / "*" / "+" / "," / ";" / "="
|
||||
do
|
||||
inspect c
|
||||
when '!' , '$' , '&' , '%'' , '(' , ')' , '*' , '+' , ',' , ';' , '=' then -- sub-delims
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
hex_digit: SPECIAL [NATURAL_32]
|
||||
-- Hexadecimal digits.
|
||||
once
|
||||
create Result.make_filled (0, 16)
|
||||
Result [0] := {NATURAL_32} 48 -- 48 '0'
|
||||
Result [1] := {NATURAL_32} 49 -- 49 '1'
|
||||
Result [2] := {NATURAL_32} 50 -- 50 '2'
|
||||
Result [3] := {NATURAL_32} 51 -- 51 '3'
|
||||
Result [4] := {NATURAL_32} 52 -- 52 '4'
|
||||
Result [5] := {NATURAL_32} 53 -- 53 '5'
|
||||
Result [6] := {NATURAL_32} 54 -- 54 '6'
|
||||
Result [7] := {NATURAL_32} 55 -- 55 '7'
|
||||
Result [8] := {NATURAL_32} 56 -- 56 '8'
|
||||
Result [9] := {NATURAL_32} 57 -- 57 '9'
|
||||
Result [10] := {NATURAL_32} 65 -- 65 'A'
|
||||
Result [11] := {NATURAL_32} 66 -- 66 'B'
|
||||
Result [12] := {NATURAL_32} 67 -- 67 'C'
|
||||
Result [13] := {NATURAL_32} 68 -- 68 'D'
|
||||
Result [14] := {NATURAL_32} 69 -- 69 'E'
|
||||
Result [15] := {NATURAL_32} 70 -- 70 'F'
|
||||
end
|
||||
|
||||
is_hexa_decimal (a_string: READABLE_STRING_GENERAL): BOOLEAN
|
||||
-- Is `a_string' a valid hexadecimal sequence?
|
||||
local
|
||||
l_convertor: like ctoi_convertor
|
||||
do
|
||||
l_convertor := ctoi_convertor
|
||||
l_convertor.parse_string_with_type (a_string, {NUMERIC_INFORMATION}.type_natural_32)
|
||||
Result := l_convertor.is_integral_integer
|
||||
end
|
||||
|
||||
hexadecimal_string_to_natural_32 (a_hex_string: READABLE_STRING_GENERAL): NATURAL_32
|
||||
-- Convert hexadecimal value `a_hex_string' to its corresponding NATURAL_32 value.
|
||||
require
|
||||
is_hexa: is_hexa_decimal (a_hex_string)
|
||||
local
|
||||
l_convertor: like ctoi_convertor
|
||||
do
|
||||
l_convertor := ctoi_convertor
|
||||
l_convertor.parse_string_with_type (a_hex_string, {NUMERIC_INFORMATION}.type_no_limitation)
|
||||
Result := l_convertor.parsed_natural_32
|
||||
end
|
||||
|
||||
ctoi_convertor: HEXADECIMAL_STRING_TO_INTEGER_CONVERTER
|
||||
-- Converter used to convert string to integer or natural.
|
||||
once
|
||||
create Result.make
|
||||
Result.set_leading_separators_acceptable (False)
|
||||
Result.set_trailing_separators_acceptable (False)
|
||||
ensure
|
||||
ctoi_convertor_not_void: Result /= Void
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 2011-2014, 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
|
||||
@@ -20,6 +20,12 @@ inherit
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
PERCENT_ENCODER
|
||||
rename
|
||||
percent_encoded_string as general_encoded_string,
|
||||
percent_decoded_string as general_decoded_string
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: READABLE_STRING_8
|
||||
@@ -27,10 +33,6 @@ feature -- Access
|
||||
create {IMMUTABLE_STRING_8} Result.make_from_string ("URL-encoded")
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has_error: BOOLEAN
|
||||
|
||||
feature -- Encoder
|
||||
|
||||
encoded_string (s: READABLE_STRING_32): STRING_8
|
||||
@@ -39,333 +41,16 @@ feature -- Encoder
|
||||
Result := general_encoded_string (s)
|
||||
end
|
||||
|
||||
general_encoded_string (s: READABLE_STRING_GENERAL): STRING_8
|
||||
-- URL-encoded value of `s'.
|
||||
local
|
||||
i, n: INTEGER
|
||||
c: CHARACTER_8
|
||||
l_code: NATURAL_32
|
||||
do
|
||||
has_error := False
|
||||
create Result.make (s.count + s.count // 10)
|
||||
n := s.count
|
||||
from i := 1 until i > n loop
|
||||
l_code := s.code (i)
|
||||
if l_code.is_valid_character_8_code then
|
||||
c := l_code.to_character_8
|
||||
inspect c
|
||||
when
|
||||
'A' .. 'Z',
|
||||
'a' .. 'z', '0' .. '9',
|
||||
'.', '-', '~', '_'
|
||||
then
|
||||
Result.extend (c)
|
||||
else
|
||||
Result.append (url_encoded_char (l_code))
|
||||
end
|
||||
else
|
||||
Result.append (url_encoded_char (l_code))
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
partial_encoded_string (s: READABLE_STRING_GENERAL; a_ignore: ARRAY [CHARACTER]): STRING_8
|
||||
-- URL-encoded value of `s'.
|
||||
local
|
||||
i, n: INTEGER
|
||||
l_code: NATURAL_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
|
||||
l_code := s.code (i)
|
||||
if l_code.is_valid_character_8_code then
|
||||
c := l_code.to_character_8
|
||||
inspect c
|
||||
when
|
||||
'A' .. 'Z',
|
||||
'a' .. 'z', '0' .. '9',
|
||||
'.', '-', '~', '_'
|
||||
then
|
||||
s8.extend (c)
|
||||
else
|
||||
if a_ignore.has (c) then
|
||||
s8.extend (c)
|
||||
else
|
||||
s8.append (url_encoded_char (l_code))
|
||||
end
|
||||
end
|
||||
else
|
||||
if a_ignore.has (c) then
|
||||
s8.extend (c)
|
||||
else
|
||||
s8.append (url_encoded_char (l_code))
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- encoder character
|
||||
|
||||
url_encoded_char (a_code: NATURAL_32): STRING_8
|
||||
do
|
||||
create Result.make (3)
|
||||
if a_code.is_valid_character_8_code then
|
||||
Result.extend ('%%')
|
||||
Result.append (a_code.to_hex_string)
|
||||
from
|
||||
until
|
||||
Result.count < 2 or else Result[2] /= '0'
|
||||
loop
|
||||
Result.remove (2)
|
||||
end
|
||||
else
|
||||
has_error := True --| Non-ascii escape not currently supported
|
||||
end
|
||||
ensure
|
||||
exists: Result /= Void
|
||||
end
|
||||
|
||||
feature -- Decoder
|
||||
|
||||
decoded_string (v: READABLE_STRING_8): STRING_32
|
||||
-- The URL-encoded equivalent of the given string
|
||||
local
|
||||
i, n: INTEGER
|
||||
c: CHARACTER
|
||||
pr: CELL [INTEGER]
|
||||
changed: BOOLEAN
|
||||
do
|
||||
has_error := False
|
||||
n := v.count
|
||||
create Result.make (n)
|
||||
from i := 1
|
||||
until i > n
|
||||
loop
|
||||
c := v.item (i)
|
||||
inspect c
|
||||
when '+' then
|
||||
changed := True
|
||||
Result.append_character ({CHARACTER_32}' ')
|
||||
when '%%' then
|
||||
-- An escaped character ?
|
||||
if i = n then
|
||||
Result.append_character (c.to_character_32)
|
||||
else
|
||||
changed := True
|
||||
create pr.put (i)
|
||||
Result.append (url_decoded_char (v, pr))
|
||||
i := pr.item
|
||||
end
|
||||
else
|
||||
Result.append_character (c.to_character_32)
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- decoded character
|
||||
|
||||
url_decoded_char (buf: STRING_8; posr: CELL [INTEGER]): STRING_32
|
||||
-- Character(s) resulting from decoding the URL-encoded string
|
||||
require
|
||||
stream_exists: buf /= Void
|
||||
posr_exists: posr /= Void
|
||||
valid_start: posr.item <= buf.count
|
||||
local
|
||||
c: CHARACTER
|
||||
i, n, nb: INTEGER
|
||||
not_a_digit: BOOLEAN
|
||||
ascii_pos, ival: INTEGER
|
||||
pos: INTEGER
|
||||
do
|
||||
--| pos is index in stream of escape character ('%')
|
||||
pos := posr.item
|
||||
create Result.make (4)
|
||||
if buf.item (pos + 1) = 'u' then
|
||||
-- An escaped Unicode (ucs2) value, from ECMA scripts
|
||||
-- Has the form: %u<n> where <n> is the UCS value
|
||||
-- of the character (two byte integer, one to 4 chars
|
||||
-- after escape sequence).
|
||||
-- UTF-8 result can be 1 to 4 characters
|
||||
n := buf.count
|
||||
from i := pos + 2
|
||||
until (i > n) or not_a_digit
|
||||
loop
|
||||
c := buf.item (i)
|
||||
if c.is_hexa_digit then
|
||||
ival := ival * 16
|
||||
if c.is_digit then
|
||||
ival := ival + (c |-| '0')
|
||||
else
|
||||
ival := ival + (c.upper |-| 'A') + 10
|
||||
end
|
||||
i := i + 1
|
||||
else
|
||||
not_a_digit := True
|
||||
end
|
||||
end
|
||||
posr.replace (i)
|
||||
-- ival is now UCS2 value; needs conversion to UTF8
|
||||
Result.append_code (ival.as_natural_32)
|
||||
nb := utf8_bytes_in_sequence (buf, pos)
|
||||
else
|
||||
-- ASCII char?
|
||||
ascii_pos := hex_to_integer_32 (buf.substring (pos+1, pos+2))
|
||||
if ascii_pos >= 0x80 and ascii_pos <= 0xff then
|
||||
-- Might be improperly escaped
|
||||
Result.append_code (ascii_pos.as_natural_32)
|
||||
posr.replace (pos + 2)
|
||||
else
|
||||
Result.append_code (ascii_pos.as_natural_32)
|
||||
posr.replace (pos + 2)
|
||||
end
|
||||
end
|
||||
ensure
|
||||
exists: Result /= Void
|
||||
end
|
||||
|
||||
feature {NONE} -- UTF8
|
||||
|
||||
utf8_bytes_in_sequence (s: STRING_8; spos: INTEGER): INTEGER
|
||||
-- If the given character is a legal first byte element in a
|
||||
-- utf8 byte sequence (aka character), then return the number
|
||||
-- of bytes in that sequence
|
||||
-- Result of zero means it's not a utf8 first byte
|
||||
require
|
||||
exists: s /= Void
|
||||
long_enough: s.count >= spos
|
||||
do
|
||||
Result := bytes_in_utf8_char (s.item (spos))
|
||||
end
|
||||
|
||||
bytes_in_utf8_char (v: CHARACTER_8): INTEGER
|
||||
-- If the given byte a legal first byte element in a utf8 sequence,
|
||||
-- then the number of bytes in that character
|
||||
-- Zero denotes an error, i.e. not a legal UTF8 char
|
||||
--
|
||||
-- The first byte of a UTF8 encodes the length
|
||||
local
|
||||
c: NATURAL_8
|
||||
do
|
||||
c := v.code.to_natural_8
|
||||
Result := 1 -- 7 bit ASCII
|
||||
if (c & 0x80) /= 0 then
|
||||
-- Hi bit means not ASCII
|
||||
Result := 0
|
||||
if (c & 0xe0) = 0xc0 then
|
||||
-- If we see a first byte as b110xxxxx
|
||||
-- then we expect a two-byte character
|
||||
Result := 2
|
||||
elseif (c & 0xf0) = 0xe0 then
|
||||
-- If we see a first byte as b1110xxxx
|
||||
-- then we expect a three-byte character
|
||||
Result := 3
|
||||
elseif (c & 0xf8) = 0xf0 then
|
||||
-- If we see a first byte as b11110xxx
|
||||
-- then we expect a four-byte character
|
||||
Result := 4
|
||||
elseif (c & 0xfc) = 0xf8 then
|
||||
-- If we see a first byte as b111110xx
|
||||
-- then we expect a five-byte character
|
||||
Result := 5
|
||||
elseif (c & 0xfe) = 0xfc then
|
||||
-- If we see a first byte as b1111110x
|
||||
-- then we expect a six-byte character
|
||||
Result := 6
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Hexadecimal and strings
|
||||
|
||||
hex_to_integer_32 (s: STRING): INTEGER_32
|
||||
-- Hexadecimal string `s' converted to INTEGER_32 value
|
||||
require
|
||||
s_not_void: s /= Void
|
||||
local
|
||||
i, nb: INTEGER;
|
||||
char: CHARACTER
|
||||
do
|
||||
nb := s.count
|
||||
|
||||
if nb >= 2 and then s.item (2) = 'x' then
|
||||
i := 3
|
||||
else
|
||||
i := 1
|
||||
end
|
||||
|
||||
from
|
||||
until
|
||||
i > nb
|
||||
loop
|
||||
Result := Result * 16
|
||||
char := s.item (i)
|
||||
if char >= '0' and then char <= '9' then
|
||||
Result := Result + (char |-| '0')
|
||||
else
|
||||
Result := Result + (char.lower |-| 'a' + 10)
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
hex_to_integer_64 (s: STRING): INTEGER_64
|
||||
-- Hexadecimal string `s' converted to INTEGER_64 value
|
||||
require
|
||||
s_not_void: s /= Void
|
||||
local
|
||||
i, nb: INTEGER;
|
||||
char: CHARACTER
|
||||
do
|
||||
nb := s.count
|
||||
|
||||
if nb >= 2 and then s.item (2) = 'x' then
|
||||
i := 3
|
||||
else
|
||||
i := 1
|
||||
end
|
||||
|
||||
from
|
||||
until
|
||||
i > nb
|
||||
loop
|
||||
Result := Result * 16
|
||||
char := s.item (i)
|
||||
if char >= '0' and then char <= '9' then
|
||||
Result := Result + (char |-| '0')
|
||||
else
|
||||
Result := Result + (char.lower |-| 'a' + 10)
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
hex_to_pointer (s: STRING): POINTER
|
||||
-- Hexadecimal string `s' converted to POINTER value
|
||||
require
|
||||
s_not_void: s /= Void
|
||||
local
|
||||
val_32: INTEGER_32
|
||||
val_64: INTEGER_64
|
||||
do
|
||||
if Pointer_bytes = Integer_64_bytes then
|
||||
val_64 := hex_to_integer_64 (s)
|
||||
($Result).memory_copy ($val_64, Pointer_bytes)
|
||||
else
|
||||
val_32 := hex_to_integer_32 (s)
|
||||
($Result).memory_copy ($val_32, Pointer_bytes)
|
||||
end
|
||||
Result := general_decoded_string (v)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Eiffel Software and others"
|
||||
copyright: "Copyright (c) 2011-2014, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -14,23 +14,6 @@ class
|
||||
|
||||
inherit
|
||||
URL_ENCODER
|
||||
redefine
|
||||
name,
|
||||
general_encoded_string,
|
||||
encoded_string, partial_encoded_string,
|
||||
decoded_string
|
||||
select
|
||||
encoded_string,
|
||||
decoded_string,
|
||||
has_error
|
||||
end
|
||||
|
||||
UTF8_ENCODER
|
||||
rename
|
||||
general_encoded_string as utf8_general_encoded_string,
|
||||
encoded_string as utf8_encoded_string,
|
||||
decoded_string as utf8_decoded_string,
|
||||
has_error as utf8_has_error
|
||||
redefine
|
||||
name
|
||||
end
|
||||
@@ -42,43 +25,8 @@ feature -- Access
|
||||
create {IMMUTABLE_STRING_8} Result.make_from_string ("UTF8-URL-encoded")
|
||||
end
|
||||
|
||||
feature -- Encoder
|
||||
|
||||
encoded_string (s: READABLE_STRING_32): STRING_8
|
||||
-- URL-encoded value of `s'.
|
||||
do
|
||||
Result := general_encoded_string (s)
|
||||
end
|
||||
|
||||
general_encoded_string (s: READABLE_STRING_GENERAL): STRING_8
|
||||
do
|
||||
Result := utf8_general_encoded_string (s)
|
||||
Result := Precursor {URL_ENCODER} (Result)
|
||||
has_error := has_error or utf8_has_error
|
||||
end
|
||||
|
||||
partial_encoded_string (s: READABLE_STRING_GENERAL; a_ignore: ARRAY [CHARACTER]): STRING_8
|
||||
-- URL-encoded value of `s'.
|
||||
do
|
||||
Result := utf8_general_encoded_string (s)
|
||||
Result := Precursor {URL_ENCODER} (Result, a_ignore)
|
||||
has_error := has_error or utf8_has_error
|
||||
end
|
||||
|
||||
feature -- Decoder
|
||||
|
||||
decoded_string (v: READABLE_STRING_8): STRING_32
|
||||
-- The URL-encoded equivalent of the given string
|
||||
do
|
||||
Result := Precursor {URL_ENCODER} (v)
|
||||
if not has_error then
|
||||
Result := utf8_decoded_string (Result)
|
||||
has_error := utf8_has_error
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "2011-2013, Eiffel Software and others"
|
||||
copyright: "Copyright (c) 2011-2014, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -34,6 +34,38 @@ feature -- Test routines
|
||||
assert ("decoded encoded string is same", u ~ s)
|
||||
end
|
||||
|
||||
feature -- Tests
|
||||
|
||||
test_valid_64_encoding
|
||||
do
|
||||
assert ("Expected encoded True:", is_valid_base64_encoding ((create {BASE64}).encoded_string ("content")))
|
||||
end
|
||||
|
||||
test_not_valid64_encoding
|
||||
do
|
||||
assert ("Expected encoded False:", not is_valid_base64_encoding ("content"))
|
||||
assert ("Expected encoded False:", not is_valid_base64_encoding ("!@#$%%^"))
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
is_valid_base64_encoding (a_string: STRING): BOOLEAN
|
||||
-- is `a_string' base64 encoded?
|
||||
local
|
||||
l_encoder: BASE64
|
||||
l_string: STRING
|
||||
l_retry: BOOLEAN
|
||||
do
|
||||
if not l_retry then
|
||||
create l_encoder
|
||||
l_string := l_encoder.decoded_string (a_string)
|
||||
Result := not l_encoder.has_error
|
||||
end
|
||||
rescue
|
||||
l_retry := True
|
||||
retry
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
@@ -21,6 +21,7 @@ feature -- Test routines
|
||||
do
|
||||
test_json_encoded_encoding ({STRING_32}"il était une fois %"Ni & Hao%" (你好) \a\b\c")
|
||||
test_json_encoded_encoding ({STRING_32}" it's `abc’ ")
|
||||
test_json_encoded_encoding ({STRING_32}"tab%Tnew line%N %"double quote %"")
|
||||
end
|
||||
|
||||
test_json_encoded_encoding (s: STRING_32)
|
||||
|
||||
@@ -22,6 +22,7 @@ feature -- Test routines
|
||||
test_url_encoded_encoding ({STRING_32}"http://domain.tld/foo/bar/script.php?test='toto'&foo=bar&title=il <20>tait une fois")
|
||||
test_url_encoded_encoding ({STRING_32}"<22>t<EFBFBD>")
|
||||
test_url_encoded_decoding ({STRING_8}"%%E9t%%E9", {STRING_32}"<22>t<EFBFBD>")
|
||||
test_url_encoded_decoding ({STRING_8}"Test%%0A", {STRING_32}"Test%N")
|
||||
|
||||
test_utf8_url_encoded_decoding ({STRING_8}"%%C3%%A9t%%C3%%A9", {STRING_32}"<22>t<EFBFBD>")
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
note
|
||||
note
|
||||
description: "[
|
||||
Eiffel tests that can be executed by testing tool.
|
||||
]"
|
||||
@@ -18,23 +18,43 @@ feature -- Test routines
|
||||
test_url_encoded_encoder
|
||||
note
|
||||
testing: "url-encoded"
|
||||
local
|
||||
utf8: STRING_8
|
||||
do
|
||||
test_utf8_decoding ("%%C3%%A9t%%C3%%A9", {STRING_32}"<22>t<EFBFBD>")
|
||||
create utf8.make_empty
|
||||
utf8.append_code (195) --+
|
||||
utf8.append_code (169) -- é
|
||||
utf8.append_code (116) -- t
|
||||
utf8.append_code (195) --+
|
||||
utf8.append_code (169) -- é
|
||||
test_utf8_decoding (utf8, {STRING_32}"été")
|
||||
|
||||
create utf8.make_empty
|
||||
utf8.append_code (228) --+
|
||||
utf8.append_code (189) --+
|
||||
utf8.append_code (160) -- 你
|
||||
|
||||
utf8.append_code (229) --+
|
||||
utf8.append_code (165) --+
|
||||
utf8.append_code (189) -- 好
|
||||
|
||||
utf8.append_code (229) --+
|
||||
utf8.append_code (144) --+
|
||||
utf8.append_code (151) -- 吗
|
||||
|
||||
test_utf8_decoding (utf8, {STRING_32}"你好吗")
|
||||
end
|
||||
|
||||
test_utf8_decoding (s: STRING_8; e: STRING_32)
|
||||
local
|
||||
url: URL_ENCODER
|
||||
u: STRING_32
|
||||
b: UTF8_ENCODER
|
||||
do
|
||||
create b
|
||||
create url
|
||||
u := b.decoded_string (url.decoded_string (s))
|
||||
u := b.decoded_string (s)
|
||||
assert ("decoded encoded string is same for %"" + s + "%"", u ~ e)
|
||||
end
|
||||
|
||||
|
||||
note
|
||||
copyright: "2011-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
|
||||
15
library/text/parser/uri_template/package.iron
Normal file
15
library/text/parser/uri_template/package.iron
Normal file
@@ -0,0 +1,15 @@
|
||||
package uri_template
|
||||
|
||||
project
|
||||
uri_template = "uri_template-safe.ecf"
|
||||
uri_template = "uri_template.ecf"
|
||||
|
||||
note
|
||||
-- title:
|
||||
-- description:
|
||||
-- tags:
|
||||
-- license:
|
||||
-- copyright:
|
||||
-- link[doc]: "Documentation" http://
|
||||
|
||||
end
|
||||
@@ -15,7 +15,7 @@ inherit
|
||||
|
||||
feature -- Matcher
|
||||
|
||||
test_uri_template_matcher
|
||||
test_uri_template_matcher_01
|
||||
note
|
||||
testing: "uri-template"
|
||||
local
|
||||
@@ -80,6 +80,19 @@ feature -- Matcher
|
||||
|
||||
end
|
||||
|
||||
test_uri_template_matcher_02
|
||||
note
|
||||
testing: "uri-template"
|
||||
local
|
||||
tpl: URI_TEMPLATE
|
||||
do
|
||||
create tpl.make ("/test/{vars}")
|
||||
uri_template_match (tpl, "/test/foo%%2Fbar", <<["vars", "foo%%2Fbar"]>>, <<>>)
|
||||
|
||||
create tpl.make ("/test{/vars}")
|
||||
uri_template_match (tpl, "/test/foo%%2Fbar/abc%%2Fdef", <<["vars", "/foo%%2Fbar/abc%%2Fdef"], ["vars[1]", "foo%%2Fbar"], ["vars[2]", "abc%%2Fdef"]>>, <<>>)
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementations
|
||||
|
||||
uri_template_mismatch (a_uri_template: URI_TEMPLATE; a_uri: STRING)
|
||||
|
||||
15
library/utility/general/error/package.iron
Normal file
15
library/utility/general/error/package.iron
Normal file
@@ -0,0 +1,15 @@
|
||||
package error
|
||||
|
||||
project
|
||||
error = "error-safe.ecf"
|
||||
error = "error.ecf"
|
||||
|
||||
note
|
||||
-- title:
|
||||
-- description:
|
||||
-- tags:
|
||||
-- license:
|
||||
-- copyright:
|
||||
-- link[doc]: "Documentation" http://
|
||||
|
||||
end
|
||||
@@ -54,9 +54,9 @@ feature -- String representation
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
debug_output: STRING_32
|
||||
do
|
||||
Result := string_representation.as_string_8
|
||||
Result := string_representation
|
||||
end
|
||||
|
||||
feature -- Change
|
||||
@@ -80,7 +80,7 @@ invariant
|
||||
name_attached: name /= Void
|
||||
|
||||
note
|
||||
copyright: "2011-2012, Eiffel Software and others"
|
||||
copyright: "2011-2014, Jocelyn Fiat, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
|
||||
@@ -260,7 +260,7 @@ feature -- Access
|
||||
has_error_implies_result_attached: has_error implies Result /= Void
|
||||
end
|
||||
|
||||
as_string_representation: STRING
|
||||
as_string_representation: STRING_32
|
||||
-- String representation of all error(s).
|
||||
require
|
||||
has_error
|
||||
@@ -269,7 +269,7 @@ feature -- Access
|
||||
Result := e.string_representation
|
||||
else
|
||||
check has_error: False end
|
||||
Result := "Error occured"
|
||||
Result := {STRING_32} "Error occured"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="all" uuid="0562209B-4C68-4E77-8B57-13CBF53D05BD" library_target="all">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="all" uuid="0562209B-4C68-4E77-8B57-13CBF53D05BD" library_target="all">
|
||||
<description>Integration project including many lib</description>
|
||||
<target name="all">
|
||||
<root all_classes="true"/>
|
||||
@@ -47,7 +47,6 @@
|
||||
<library name="uri_template" location="..\library\text\parser\uri_template\uri_template-safe.ecf" readonly="false"/>
|
||||
<library name="wizard" location="..\tools\ise_wizard\ewf_ise_wizard-safe.ecf" readonly="false"/>
|
||||
<library name="wsf" location="..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_policy_driven" location="..\library\server\wsf\wsf_policy_driven-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_all" location="..\library\server\wsf\connector\all-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_cgi" location="..\library\server\wsf\connector\cgi-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_extension" location="..\library\server\wsf\wsf_extension-safe.ecf" readonly="false"/>
|
||||
@@ -55,6 +54,7 @@
|
||||
<library name="wsf_libfcgi" location="..\library\server\wsf\connector\libfcgi-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_nino" location="..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_openshift" location="..\library\server\wsf\connector\openshift-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_policy_driven" location="..\library\server\wsf\wsf_policy_driven-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_router_context" location="..\library\server\wsf\wsf_router_context-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_session" location="..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/>
|
||||
</target>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="all" uuid="1172C52C-6979-4293-8F01-80FADA5A2B69" library_target="all_stable">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="all" uuid="1172C52C-6979-4293-8F01-80FADA5A2B69" library_target="all_stable">
|
||||
<description>Integration project including many lib</description>
|
||||
<target name="all_stable">
|
||||
<root all_classes="true"/>
|
||||
@@ -10,45 +10,45 @@
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard">
|
||||
</option>
|
||||
<library name="restbucks" location="..\examples\restbucksCRUD\restbucks-safe.ecf" readonly="false"/>
|
||||
<library name="client" location="..\examples\restbucksCRUD\client\client-safe.ecf" readonly="false"/>
|
||||
<library name="upload_image" location="..\examples\upload_image\upload_image-safe.ecf" readonly="false"/>
|
||||
<library name="http_client" location="..\library\network\http_client\http_client-safe.ecf" readonly="false"/>
|
||||
<library name="conneg" location="..\library\network\protocol\content_negotiation\conneg-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\library\network\protocol\http\http-safe.ecf" readonly="false"/>
|
||||
<library name="openid" location="..\library\security\openid\consumer\openid-safe.ecf" readonly="false"/>
|
||||
<library name="demo-1" location="..\library\security\openid\consumer\demo\demo-safe.ecf" readonly="false"/>
|
||||
<library name="http_authorization" location="..\library\server\authentication\http_authorization\http_authorization-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\library\server\ewsgi\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi_spec" location="..\library\server\ewsgi\ewsgi_spec-safe.ecf" readonly="false"/>
|
||||
<library name="connector_cgi" location="..\library\server\ewsgi\connectors\cgi\cgi-safe.ecf" readonly="false"/>
|
||||
<library name="connector_libfcgi" location="..\library\server\ewsgi\connectors\libfcgi\libfcgi-safe.ecf" readonly="false"/>
|
||||
<library name="connector_nino" location="..\library\server\ewsgi\connectors\nino\nino-safe.ecf" readonly="false"/>
|
||||
<library name="connector_null" location="..\library\server\ewsgi\connectors\null\null-safe.ecf" readonly="false"/>
|
||||
<library name="hello_world" location="..\library\server\ewsgi\examples\hello_world\hello-safe.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\library\server\libfcgi\libfcgi-safe.ecf" readonly="false"/>
|
||||
<library name="wsf" location="..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_extension" location="..\library\server\wsf\wsf_extension-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_router_context" location="..\library\server\wsf\wsf_router_context-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_session" location="..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_all" location="..\library\server\wsf\connector\all-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_cgi" location="..\library\server\wsf\connector\cgi-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_libfcgi" location="..\library\server\wsf\connector\libfcgi-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_nino" location="..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_openshift" location="..\library\server\wsf\connector\openshift-safe.ecf" readonly="false"/>
|
||||
<library name="conneg" location="..\library\network\protocol\content_negotiation\conneg-safe.ecf" readonly="false"/>
|
||||
<library name="default_cgi" location="..\library\server\wsf\default\cgi-safe.ecf" readonly="false"/>
|
||||
<library name="default_libfcgi" location="..\library\server\wsf\default\libfcgi-safe.ecf" readonly="false"/>
|
||||
<library name="default_nino" location="..\library\server\wsf\default\nino-safe.ecf" readonly="false"/>
|
||||
<library name="default_openshift" location="..\library\server\wsf\default\openshift-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_html" location="..\library\server\wsf_html\wsf_html-safe.ecf" readonly="false"/>
|
||||
<library name="demo-1" location="..\library\security\openid\consumer\demo\demo-safe.ecf" readonly="false"/>
|
||||
<library name="encoder" location="..\library\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||
<library name="uri_template" location="..\library\text\parser\uri_template\uri_template-safe.ecf" readonly="false"/>
|
||||
<library name="error" location="..\library\utility\general\error\error-safe.ecf" readonly="false"/>
|
||||
<library name="precomp_wsf-mt" location="..\precomp\wsf-mt-safe.ecf" readonly="false"/>
|
||||
<library name="precomp_wsf" location="..\precomp\wsf-safe.ecf" readonly="false"/>
|
||||
<library name="precomp_wsf-scoop-safe" location="..\precomp\wsf-scoop-safe.ecf" readonly="false"/>
|
||||
<library name="wizard" location="..\tools\ise_wizard\ewf_ise_wizard-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi" location="..\library\server\ewsgi\ewsgi-safe.ecf" readonly="false"/>
|
||||
<library name="ewsgi_spec" location="..\library\server\ewsgi\ewsgi_spec-safe.ecf" readonly="false"/>
|
||||
<library name="hello_world" location="..\library\server\ewsgi\examples\hello_world\hello-safe.ecf" readonly="false"/>
|
||||
<library name="http" location="..\library\network\protocol\http\http-safe.ecf" readonly="false"/>
|
||||
<library name="http_authorization" location="..\library\server\authentication\http_authorization\http_authorization-safe.ecf" readonly="false"/>
|
||||
<library name="http_client" location="..\library\network\http_client\http_client-safe.ecf" readonly="false"/>
|
||||
<library name="libfcgi" location="..\library\server\libfcgi\libfcgi-safe.ecf" readonly="false"/>
|
||||
<library name="notification_email" location="..\library\runtime\process\notification_email\notification_email-safe.ecf" readonly="false"/>
|
||||
<library name="openid" location="..\library\security\openid\consumer\openid-safe.ecf" readonly="false"/>
|
||||
<library name="precomp_wsf" location="..\precomp\wsf-safe.ecf" readonly="false"/>
|
||||
<library name="precomp_wsf-mt" location="..\precomp\wsf-mt-safe.ecf" readonly="false"/>
|
||||
<library name="precomp_wsf-scoop-safe" location="..\precomp\wsf-scoop-safe.ecf" readonly="false"/>
|
||||
<library name="restbucks" location="..\examples\restbucksCRUD\restbucks-safe.ecf" readonly="false"/>
|
||||
<library name="upload_image" location="..\examples\upload_image\upload_image-safe.ecf" readonly="false"/>
|
||||
<library name="uri_template" location="..\library\text\parser\uri_template\uri_template-safe.ecf" readonly="false"/>
|
||||
<library name="wizard" location="..\tools\ise_wizard\ewf_ise_wizard-safe.ecf" readonly="false"/>
|
||||
<library name="wsf" location="..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_all" location="..\library\server\wsf\connector\all-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_cgi" location="..\library\server\wsf\connector\cgi-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_extension" location="..\library\server\wsf\wsf_extension-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_html" location="..\library\server\wsf_html\wsf_html-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_libfcgi" location="..\library\server\wsf\connector\libfcgi-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_nino" location="..\library\server\wsf\connector\nino-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_openshift" location="..\library\server\wsf\connector\openshift-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_router_context" location="..\library\server\wsf\wsf_router_context-safe.ecf" readonly="false"/>
|
||||
<library name="wsf_session" location="..\library\server\wsf\wsf_session-safe.ecf" readonly="false"/>
|
||||
</target>
|
||||
<target name="all_stable_windows" extends="all_stable">
|
||||
<description>Compiling as Windows , on other platforms than Windows</description>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-10-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-10-0 http://www.eiffel.com/developers/xml/configuration-1-10-0.xsd" name="wizard" uuid="F881A707-745E-4C6D-90D1-F820EE3B1470" library_target="wizard">
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="wizard" uuid="F881A707-745E-4C6D-90D1-F820EE3B1470" library_target="wizard">
|
||||
<target name="wizard">
|
||||
<root class="EWF_WIZARD" feature="make"/>
|
||||
<file_rule>
|
||||
|
||||
Reference in New Issue
Block a user