Merge branch 'master' of github.com:EiffelWebFramework/EWF into widget_integration

This commit is contained in:
2014-07-07 10:30:42 +02:00
318 changed files with 14865 additions and 10865 deletions

142
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,142 @@
# Contributing to this project
Please take a moment to review this document in order to make the contribution
process easy and effective for everyone involved.
Following these guidelines helps to communicate that you respect the time of
the developers managing and developing this open source project. In return,
they should reciprocate that respect in addressing your issue or assessing
patches and features.
## Using the issue tracker
The issue tracker is the preferred channel for [bug reports](#bugs),
[features requests](#features) and [submitting pull
requests](#pull-requests), but please respect the following restrictions:
* Please **do not** use the issue tracker for personal support requests (use
[Stack Overflow](http://stackoverflow.com) or IRC).
* Please **do not** derail or troll issues. Keep the discussion on topic and
respect the opinions of others.
<a name="bugs"></a>
## Bug reports
A bug is a _demonstrable problem_ that is caused by the code in the repository.
Good bug reports are extremely helpful - thank you!
Guidelines for bug reports:
1. **Use the GitHub issue search** &mdash; check if the issue has already been
reported.
2. **Check if the issue has been fixed** &mdash; try to reproduce it using the
latest `master` or development branch in the repository.
3. **Isolate the problem** &mdash; ideally create a [reduced test
case](http://css-tricks.com/6263-reduced-test-cases/) and a live example.
A good bug report shouldn't leave others needing to chase you up for more
information. Please try to be as detailed as possible in your report. What is
your environment? What steps will reproduce the issue? What browser(s) and OS
experience the problem? What would you expect to be the outcome? All these
details will help people to fix any potential bugs.
Example:
> Short and descriptive example bug report title
>
> A summary of the issue and the browser/OS environment in which it occurs. If
> suitable, include the steps required to reproduce the bug.
>
> 1. This is the first step
> 2. This is the second step
> 3. Further steps, etc.
>
> `<url>` - a link to the reduced test case
>
> Any other information you want to share that is relevant to the issue being
> reported. This might include the lines of code that you have identified as
> causing the bug, and potential solutions (and your opinions on their
> merits).
<a name="features"></a>
## Feature requests
Feature requests are welcome. But take a moment to find out whether your idea
fits with the scope and aims of the project. It's up to *you* to make a strong
case to convince the project's developers of the merits of this feature. Please
provide as much detail and context as possible.
<a name="pull-requests"></a>
## Pull requests
Good pull requests - patches, improvements, new features - are a fantastic
help. They should remain focused in scope and avoid containing unrelated
commits.
**Please ask first** before embarking on any significant pull request (e.g.
implementing features, refactoring code, porting to a different language),
otherwise you risk spending a lot of time working on something that the
project's developers might not want to merge into the project.
Please adhere to the coding conventions used throughout a project (indentation,
accurate comments, etc.) and any other requirements (such as test coverage).
Adhering to the following this process is the best way to get your work
included in the project:
1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
and configure the remotes:
```bash
# Clone your fork of the repo into the current directory
git clone https://github.com/<your-username>/<repo-name>
# Navigate to the newly cloned directory
cd <repo-name>
# Assign the original repo to a remote called "upstream"
git remote add upstream https://github.com/<upstream-owner>/<repo-name>
```
2. If you cloned a while ago, get the latest changes from upstream:
```bash
git checkout <dev-branch>
git pull upstream <dev-branch>
```
3. Create a new topic branch (off the main project development branch) to
contain your feature, change, or fix:
```bash
git checkout -b <topic-branch-name>
```
4. Commit your changes in logical chunks. Please adhere to these [git commit
message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
or your code is unlikely be merged into the main project. Use Git's
[interactive rebase](https://help.github.com/articles/interactive-rebase)
feature to tidy up your commits before making them public.
5. Locally merge (or rebase) the upstream development branch into your topic branch:
```bash
git pull [--rebase] upstream <dev-branch>
```
6. Push your topic branch up to your fork:
```bash
git push origin <topic-branch-name>
```
7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
with a clear title and description.
**IMPORTANT**: By submitting a patch, you agree to allow the project owner to
license your work under the same license as that used by the project.

View File

@@ -3,6 +3,27 @@
## Overview
The Eiffel Web Framework (EWF) provides Eiffel users with a layer to build anything on top of the http protocol such as websites, web API/services.
This layer is multi-platform: it can be set on Windows, Linux operating systems, and in addition it can run on top of any httpd servers such as Apache2, IIS, nginx, lighttpd. EWF includes as well a standalone httpd web server component, written in Eiffel, which enables users to run easily a web server on their machine, or even embed this component in any application written with Eiffel.
Currently EWF offers a collection of Eiffel libraries designed to be integrated with each others, and among other functionalities, it give simple access to the request data, to handle content negotiation, url dispatcher, integrate with openid system, and so on.
There is a growing ecosystem around EWF, that provides useful components:
* OpenID and OAuth consumer library
* Various hypermedia format such as HAL, Collection+json, …
* Websocket server and client
* Template engine
* API Auto-documentation with swagger
* A simple experimental CMS.
* ...
So if you want to build a website, a web api, RESTful service, …or even if you want to consume other web api, EWF is a solution.
EWF brings with it all the advantages of the Eiffel technology and tools with its powerful features such as Design by Contract, debugging, testing tools which enable to build efficient systems expected to be repeatedly refined, extended, and improved in a predictable and controllable way so as to become with time bugfree systems. Enjoy the full power of debugging your web server application from the IDE.
## Project
Official project site for Eiffel Web Framework:
* http://eiffelwebframework.github.com/EWF/
@@ -14,10 +35,14 @@ 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
* Developped using EiffelStudio 7.3 (on Windows, Linux)
* Tested using EiffelStudio 7.2 with "jenkins" CI server (not anymore compatible with 6.8 due to use of `TABLE_ITERABLE')
* Compiling from EiffelStudio 7.2 to 13.11 and more recent version of the compiler.
* Developped using EiffelStudio 13.11 (on Windows, Linux)
* Tested using EiffelStudio 13.11 with "jenkins" CI server (not anymore compatible with 6.8 due to use of `TABLE_ITERABLE')
* The code have to allow __void-safe__ compilation and non void-safe system (see [more about void-safety](http://docs.eiffel.com/book/method/void-safe-programming-eiffel) )
## How to get the source code?
@@ -41,7 +66,7 @@ Using git
### protocol
* __http__: HTTP related classes, constants for status code, content types, ... [read more](library/protocol/http)
* __uri_template__: URI Template library (parsing and expander) [read more](library/protocol/uri_template)
* __CONNEG__: CONNEG library (Content-type Negociation) [read more](library/protocol/CONNEG)
* __CONNEG__: Content negotiation library (Content-type Negociation) [read more](library/protocol/content_negotiation)
### client
* __http_client__: simple HTTP client based on cURL [read more](library/client/http_client)
@@ -61,6 +86,23 @@ Using git
## Examples
..
## Contributing to this project
Anyone and everyone is welcome to contribute. Please take a moment to
review the [guidelines for contributing](CONTRIBUTING.md).
* [Bug reports](CONTRIBUTING.md#bugs)
* [Feature requests](CONTRIBUTING.md#features)
* [Pull requests](CONTRIBUTING.md#pull-requests)
## Community
Keep track of development and community news.
* Follow [@EiffelWeb](https://twitter.com/EiffelWeb) on Twitter
* Follow our [page](https://plus.google.com/u/0/110650349519032194479) and [community](https://plus.google.com/communities/110457383244374256721) on Google+
* Have a question that's not a feature request or bug report? [Ask on the mailing list](http://groups.google.com/group/eiffel-web-framework)
For more information please have a look at the related wiki:
* https://github.com/EiffelWebFramework/EWF/wiki

View File

@@ -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"/>

View File

@@ -1 +0,0 @@

View File

@@ -0,0 +1,9 @@
# Set default behaviour, in case users don't have core.autocrlf set.
* text=auto
# Explicitly declare text files we want to always be normalized and converted
# to native line endings on checkout.
*.e text
*.ecf text
*.bat text
*.json text

View File

@@ -92,6 +92,8 @@ history.txt.
Version Date Description
------- ---- -----------
0.5.0 2013-11-dd Added JSON_ITERATOR, simplified JSON_OBJECT
0.4.0 2012-12-12 Updated documentation URI
0.3.0 2011-07-06 JSON Factory Converters
0.2.0 2010-02-07 Adapted to EiffelStudio 6.4 or later, supports void-safety
0.1.0 2010-02-07 First release, Adapted to SmartEiffel 1.2r7 and EiffelStudio 6.2 or previous

View File

@@ -1,6 +1,5 @@
note
description: "Objects that ..."
author: ""
date: "$Date$"
revision: "$Revision$"
@@ -15,7 +14,7 @@ feature -- Access
template_content: STRING
l_last_string: detachable STRING
do
create l_file.make (a_path)
create l_file.make_with_name (a_path)
-- We perform several checks until we make a real attempt to open the file.
if not l_file.exists then
print ("error: '" + a_path + "' does not exist%N")

View File

@@ -0,0 +1,60 @@
note
description:
"JSON Iterator"
pattern: "Iterator visitor"
author: "Jocelyn Fiat"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
date: "2013/08/01"
revision: "Revision 0.1"
deferred class
JSON_ITERATOR
inherit
JSON_VISITOR
feature -- Visitor Pattern
visit_json_array (a_json_array: JSON_ARRAY)
-- Visit `a_json_array'.
do
across
a_json_array as c
loop
c.item.accept (Current)
end
end
visit_json_boolean (a_json_boolean: JSON_BOOLEAN)
-- Visit `a_json_boolean'.
do
end
visit_json_null (a_json_null: JSON_NULL)
-- Visit `a_json_null'.
do
end
visit_json_number (a_json_number: JSON_NUMBER)
-- Visit `a_json_number'.
do
end
visit_json_object (a_json_object: JSON_OBJECT)
-- Visit `a_json_object'.
do
across
a_json_object as c
loop
c.item.accept (Current)
end
end
visit_json_string (a_json_string: JSON_STRING)
-- Visit `a_json_string'.
do
end
end

View File

@@ -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="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>

View File

@@ -1,8 +1,8 @@
note
description: "A JSON converter for HASH_TABLE [ANY, HASHABLE]"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
date: "$Date: 2014-01-30 15:27:41 +0100 (jeu., 30 janv. 2014) $"
revision: "$Revision: 94128 $"
file: "$HeadURL: $"
class JSON_HASH_TABLE_CONVERTER
@@ -27,34 +27,20 @@ feature -- Access
feature -- Conversion
from_json (j: attached like to_json): like object
local
keys: ARRAY [JSON_STRING]
i: INTEGER
h: detachable HASHABLE
jv: detachable JSON_VALUE
a: detachable ANY
do
keys := j.current_keys
create Result.make (keys.count)
from
i := 1
until
i > keys.count
create Result.make (j.count)
across
j as ic
loop
h ?= json.object (keys [i], Void)
check h /= Void end
jv := j.item (keys [i])
if jv /= Void then
a := json.object (jv, Void)
if a /= Void then
Result.put (a, h)
if attached json.object (ic.item, Void) as l_object then
if attached {HASHABLE} json.object (ic.key, Void) as h then
Result.put (l_object, h)
else
check a_attached: a /= Void end
check key_is_hashable: False end
end
else
check j_has_item: False end
check object_attached: False end
end
i := i + 1
end
end
@@ -62,7 +48,6 @@ feature -- Conversion
local
c: HASH_TABLE_ITERATION_CURSOR [ANY, HASHABLE]
js: JSON_STRING
jv: detachable JSON_VALUE
failed: BOOLEAN
do
create Result.make
@@ -76,8 +61,7 @@ feature -- Conversion
else
create js.make_json (c.key.out)
end
jv := json.value (c.item)
if jv /= Void then
if attached json.value (c.item) as jv then
Result.put (jv, js)
else
failed := True

View File

@@ -18,6 +18,8 @@ class
inherit
JSON_VALUE
ITERABLE [JSON_VALUE]
DEBUG_OUTPUT
create
@@ -69,6 +71,14 @@ feature -- Visitor pattern
a_visitor.visit_json_array (Current)
end
feature -- Access
new_cursor: ITERATION_CURSOR [JSON_VALUE]
-- Fresh cursor associated with current structure
do
Result := values.new_cursor
end
feature -- Mesurement
count: INTEGER
@@ -87,14 +97,40 @@ feature -- Status report
feature -- Change Element
add (value: JSON_VALUE)
put_front (v: JSON_VALUE)
require
value_not_null: value /= void
v_not_void: v /= Void
do
values.extend (value)
values.put_front (v)
ensure
has_new_value: old values.count + 1 = values.count and
values.has (value)
values.first = v
end
add, extend (v: JSON_VALUE)
require
v_not_void: v /= Void
do
values.extend (v)
ensure
has_new_value: old values.count + 1 = values.count and
values.has (v)
end
prune_all (v: JSON_VALUE)
-- Remove all occurrences of `v'.
require
v_not_void: v /= Void
do
values.prune_all (v)
ensure
not_has_new_value: not values.has (v)
end
wipe_out
-- Remove all items.
do
values.wipe_out
end
feature -- Report
@@ -118,6 +154,7 @@ feature -- Conversion
array_representation: ARRAYED_LIST [JSON_VALUE]
-- Representation as a sequences of values
-- be careful, modifying the return object may have impact on the original JSON_ARRAY object
do
Result := values
end
@@ -127,7 +164,7 @@ feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := count.out
Result := count.out + " item(s)"
end
feature {NONE} -- Implementation

View File

@@ -8,7 +8,7 @@ note
object
{}
{"key","value"}
{"key": "value"}
]"
author: "Javier Velilla"
@@ -24,6 +24,8 @@ inherit
TABLE_ITERABLE [JSON_VALUE, JSON_STRING]
DEBUG_OUTPUT
create
make
@@ -52,6 +54,67 @@ feature -- Change Element
object.extend (l_value, key)
end
put_string (value: READABLE_STRING_GENERAL; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
require
key_not_present: not has_key (key)
local
l_value: JSON_STRING
do
create l_value.make_json_from_string_32 (value.as_string_32)
put (l_value, key)
end
put_integer (value: INTEGER_64; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
require
key_not_present: not has_key (key)
local
l_value: JSON_NUMBER
do
create l_value.make_integer (value)
put (l_value, key)
end
put_natural (value: NATURAL_64; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
require
key_not_present: not has_key (key)
local
l_value: JSON_NUMBER
do
create l_value.make_natural (value)
put (l_value, key)
end
put_real (value: DOUBLE; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
require
key_not_present: not has_key (key)
local
l_value: JSON_NUMBER
do
create l_value.make_real (value)
put (l_value, key)
end
put_boolean (value: BOOLEAN; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
require
key_not_present: not has_key (key)
local
l_value: JSON_BOOLEAN
do
create l_value.make_boolean (value)
put (l_value, key)
end
replace (value: detachable JSON_VALUE; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
@@ -65,6 +128,68 @@ feature -- Change Element
object.force (l_value, key)
end
replace_with_string (value: READABLE_STRING_GENERAL; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
local
l_value: JSON_STRING
do
create l_value.make_json_from_string_32 (value.as_string_32)
replace (l_value, key)
end
replace_with_integer (value: INTEGER_64; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
local
l_value: JSON_NUMBER
do
create l_value.make_integer (value)
replace (l_value, key)
end
replace_with_with_natural (value: NATURAL_64; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
local
l_value: JSON_NUMBER
do
create l_value.make_natural (value)
replace (l_value, key)
end
replace_with_real (value: DOUBLE; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
local
l_value: JSON_NUMBER
do
create l_value.make_real (value)
replace (l_value, key)
end
replace_with_boolean (value: BOOLEAN; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
local
l_value: JSON_BOOLEAN
do
create l_value.make_boolean (value)
replace (l_value, key)
end
remove (key: JSON_STRING)
-- Remove item indexed by `key' if any.
do
object.remove (key)
end
wipe_out
-- Reset all items to default values; reset status.
do
object.wipe_out
end
feature -- Access
has_key (key: JSON_STRING): BOOLEAN
@@ -95,7 +220,8 @@ feature -- Access
local
t: HASH_TABLE [JSON_VALUE, JSON_STRING]
do
Result := "{"
create Result.make (2)
Result.append_character ('{')
from
t := map_representation
t.start
@@ -103,7 +229,7 @@ feature -- Access
t.after
loop
Result.append (t.key_for_iteration.representation)
Result.append (":")
Result.append_character (':')
Result.append (t.item_for_iteration.representation)
t.forth
if not t.after then
@@ -177,7 +303,7 @@ feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := object.count.out
Result := count.out + " item(s)"
end
feature {NONE} -- Implementation
@@ -186,6 +312,6 @@ feature {NONE} -- Implementation
-- Value container
invariant
object_not_null: object /= Void
object_not_void: object /= Void
end

View File

@@ -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
@@ -274,7 +367,7 @@ feature {NONE} -- Implementation
end
escaped_json_string_32 (s: READABLE_STRING_32): STRING_8
-- JSON string with '"' and '\' characters and unicode escaped
-- JSON string with '"' and '\' characters and Unicode escaped
require
s_not_void: s /= Void
local
@@ -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

View File

@@ -357,7 +357,7 @@ feature -- Commands
end
read_unicode: STRING
-- Read unicode and return value
-- Read Unicode and return value
local
i: INTEGER
do
@@ -449,7 +449,7 @@ feature {NONE} -- Implementation
end
is_valid_unicode (a_unicode: STRING): BOOLEAN
-- is 'a_unicode' a valid unicode based on this regular expression
-- is 'a_unicode' a valid Unicode based on this regular expression
-- "\\u[0-9a-fA-F]{4}"
local
i: INTEGER

View File

@@ -1,4 +1,4 @@
{"menu": {
{ "menu": {
"id": "file",
"value": "File",
"popup": {

View File

@@ -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
--
@@ -475,8 +496,38 @@ feature -- JSON_FROM_FILE
json_value: detachable JSON_VALUE
json_file_from (fn: STRING): detachable STRING
local
f: RAW_FILE
l_path: STRING
test_dir: STRING
i: INTEGER
do
Result := file_reader.read_json_from (test_dir + fn)
test_dir := (create {EXECUTION_ENVIRONMENT}).current_working_directory
test_dir.append_character ((create {OPERATING_ENVIRONMENT}).directory_separator)
l_path := test_dir + fn
create f.make_with_name (l_path)
if f.exists then
-- Found json file
else
-- before EiffelStudio 7.3 , the current dir of autotest execution was not the parent dir of ecf but something like
-- ..json\test\autotest\test_suite\EIFGENs\test_suite\Testing\execution\TEST_JSON_SUITE.test_json_fail1\..\..\..\..\..\fail1.json
from
i := 5
until
i = 0
loop
test_dir.append_character ('.')
test_dir.append_character ('.')
test_dir.append_character ((create {OPERATING_ENVIRONMENT}).directory_separator)
i := i - 1
end
l_path := test_dir + fn
end
create f.make_with_name (l_path)
if f.exists then
Result := file_reader.read_json_from (l_path)
end
assert ("File contains json data", Result /= Void)
end
@@ -485,30 +536,9 @@ feature -- JSON_FROM_FILE
create Result.make_parser (a_string)
end
test_dir: STRING
local
i: INTEGER
do
Result := (create {EXECUTION_ENVIRONMENT}).current_working_directory
Result.append_character ((create {OPERATING_ENVIRONMENT}).directory_separator)
-- The should looks like
-- ..json\test\autotest\test_suite\EIFGENs\test_suite\Testing\execution\TEST_JSON_SUITE.test_json_fail1\..\..\..\..\..\fail1.json
from
i := 5
until
i = 0
loop
Result.append_character ('.')
Result.append_character ('.')
Result.append_character ((create {OPERATING_ENVIRONMENT}).directory_separator)
i := i - 1
end
-- Result := "/home/jvelilla/work/project/Eiffel/ejson_dev/trunk/test/autotest/test_suite/"
end
invariant
file_reader /= Void
end

View File

@@ -1,13 +1,13 @@
This project is a community project
## Mailing list ##
- Google group: http://groups.google.com/group/eiffel-web-framework
- Google group: [http://groups.google.com/group/eiffel-web-framework](http://groups.google.com/group/eiffel-web-framework)
## Materials ##
- wiki: github wiki at https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki
- Shared documents: on google docs at http://goo.gl/M8WLP
- source code: git repository at https://github.com/Eiffel-World/Eiffel-Web-Framework
- Proposal from Paul Cohen for a EWSGI spec at http://eiffel.seibostudios.se/wiki/EWSGI
- wiki: github wiki at [https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki](https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki)
- Shared documents: on google docs at [http://goo.gl/M8WLP](http://goo.gl/M8WLP)
- source code: git repository at [https://github.com/Eiffel-World/Eiffel-Web-Framework](https://github.com/Eiffel-World/Eiffel-Web-Framework)
- Proposal from Paul Cohen for a EWSGI spec at [http://eiffel.seibostudios.se/wiki/EWSGI](http://eiffel.seibostudios.se/wiki/EWSGI)
## Main contributors ##
- **jfiat**: Jocelyn Fiat (Eiffel Software)

48
doc/wiki/Connectors.md Normal file
View File

@@ -0,0 +1,48 @@
The main goal of the connectors is to let you choose a target at compile time.
This allows you to concentrate on your business during development time and then decide which target you choose at deployment time.
The current connectors are:
* Nino
* FastCGI
* CGI
* OpenShift
The most widely used workflow is to use Nino on your development machine and FastCGI on your production server.
Nino being a web server written entirely in Eiffel, you can inspect your HTTP requests and respones in EiffelStudio which is great during development.
On the other hand, FastCGI is great at handling concurrent requests and coupled with Apache (or another web production server), you don't even need to worry about the lifecyle of your application (creation and destruction) as Apache will do it for you!
Let's now dig into each of the connecters.
# Nino
Nino is a web server entirely written in Eiffel.
The goal of Nino is to provide a simple web server for development (like Java, Python and Ruby provide).
Nino is currently maintained by Javier Velilla and the repository can be found here: https://github.com/jvelilla/EiffelWebNino
# FastCGI
FastCGI is a protocol for interfacing an application server with a web server.
It is an improvement over CGI as FastCGI supports long running processes, i.e. processes than can handle multipe requests during their lifecyle. CGI, on the other hand, launches a new process for every new request which is quite time consuming.
FastCGI is implemented by every major web servers: Apache, IIS, Nginx, ...
We recommend to use FastCGI instead of CGI as it is way more faster.
You can read more about FastCGI here: http://www.fastcgi.com/
# CGI
CGI predates FastCGI and is also a protocol for interfacing an application server with a web server.
His main drawback (and the reason why FastCGI was created) is that it launches a new process for every new request, which is quite time consuming.
We recommend to use FastCGI instead of CGI as it is way more faster.
# OpenShift
OpenShift is a cloud computing platform as a service product from Red Hat.
It basically let's you run your application in the cloud.
More informations are available here: https://www.openshift.com
# Writing your own
It's fairly easy to write your own connector. Just inherit from these classes:
* WGI_CONNECTOR
* WGI_ERROR_STREAM
* WGI_INPUT_STREAM
* WGI_OUTPUT_STREAM
* WSF_SERVICE_LAUNCHER

View File

@@ -0,0 +1 @@
See WSF_ROUTER

209
doc/wiki/Documentation.md Normal file
View File

@@ -0,0 +1,209 @@
# Current Status
* Official repository: <https://github.com/EiffelWebFramework/EWF>
* Official website: <http://eiffelwebframework.github.io/EWF/getting-started/>
# What is EWF?
Eiffel Web Framework, is mainly a collection of Eiffel libraries designed to be integrated with each other. One benefit is that it supports all core HTTP features, so enable you embrace HTTP as an application protocol to develop web applications. So you do not need to adapt your applications to the web, instead you use the web power. It means you can build different kind of web applications, from Web APIs following the Hypermedia API style (REST style), CRUD web services or just conventional web applications building a session on top of an stateless protocol.
# EWF core/kernel
> The Web Server Foundation (WSF\_) is the core of the framework. It is compliant with the EWSGI interface (WGI\_).
To build a web [service](#service), the framework provides a set of core components to launch the service, for each [request](#request-and-response), access the data, and send the [response](#request-and-response).
The framework also provides a router component to help dispatching the incoming request.
A service can be a web api, a web interface, … what ever run on top of HTTP.
<a name="wiki-service"></a>
<a name="service"></a>
# Service
> see interface: **WSF_SERVICE**
Each incoming http request is processed by the following routine.
> `{WSF_SERVICE}.execute (req: WSF_REQUEST; res: WSF_RESPONSE)`
This is the low level of the framework, at this point, `req` provides access to the query and form parameters, input data, headers, ... as specified by the Common Gateway Interface (CGI).
The response `res` is the interface to send data back to the client.
For convenience, the framework provides richer service interface that handles the most common needs (filter, router, ...).
> [Learn more about service](Documentation__Service)
<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**
Any incoming http request is represented by an new object of type **WSF_REQUEST**.
**WSF_REQUEST** provides access to
+ __meta variables__: CGI variables (coming from the request http header)
+ __query parameters__: from the uri ex: `?q=abc&type=pdf`
+ __input data__: the message of the request, if this is a web form, this is parsed to build the form parameters. It can be retrieved once.
+ __form parameters__: standard parameters from the request input data.
- typically available when a web form is sent using POST as content of type `multipart/form-data` or `application/x-www-form-urlencoded`
- (advanced usage: it is possible to write mime handler that can processed other type of content, even custom format.)
+ __uploaded files__: if files are uploaded, their value will be available from the form parameters, and from the uploaded files as well.
+ __cookies variable__: cookies extracted from the http header.
+ __path parameters__: note this is related to the router and carry the semantic of the mapping (see the section on router )
+ __execution variables__: used by the application to keep value associated with the request.
The **WSF_RESPONSE** represents the communication toward the client, a service need to provide correct headers, and content. For instance the `Content-Type`, and `Content-Length`. It also allows to send data with chunked encoding.
> [Learn more about request](Documentation__Request) and [about response](Documentation__Response)
<a name="wiki-connector"></a>
<a name="connector"></a>
# Connectors:
> see **WGI_CONNECTOR**
Using EWF, your service is built on top of underlying httpd solution/connectors.
Currently 3 main connectors are available:
* __CGI__: following the CGI interface, this is an easy solution to run the service on any platform.
* __libFCGI__: based on the libfcgi solution, this can be used with Apache, IIS, nginx, ...
* __nino__: a standalone server: Eiffel Web Nino allow you to embed a web server anywhere, on any platform without any dependencies on other httpd server.
At compilation time, you can use a default connector (by using the associated default lib), but you can also use a mixed of them and choose which one to execute at runtime.
It is fairly easy to add new connector, it just has to follow the EWSGI interface
> [Learn more about connector](Documentation__Connector)
<a name="wiki-router"></a>
<a name="router"></a>
# Router or Request Dispatcher:
> Routes HTTP requests to the proper execution code
A web application needs to have a clean and elegant URL scheme, and EWF provides a router component to design URLs.
The association between a URL pattern and the code handling the URL request is called a Router mapping in EWF.
EWF provides 3 main kinds of mappings
+ __URI__: any URL with path being the specified uri.
- example: “/users/” redirects any “/users/” and “/users/?query=...”
+ __URI-template__: any URL matching the specified URI-template
- example: “/project/{name}/” redirects any “/project/foo” or “/project/bar”
+ __Starts-with__: any URL starting with the specified path
Note: in the future, a Regular-Expression based kind will be added in the future, and it is possible to use custom mapping on top of EWF.
Code:
router.map ( create {WSF_URI_TEMPLATE_MAPPING}.make (
“/project/{name}”, project_handler)
)
-- And precising the request methods
router.map_with_request_methods ( ... , router.methods_GET_POST)
In the previous code, the `project_handler` is an object conforming to **WSF_HANDLER**, that will process the incoming requests matching URI-template “/project/{name}”.
Usually, the service will inherit from WSF_ROUTED_SERVICE, which has a `router` attribute.
Configuring the URL scheme is done by implementing `{WSF_ROUTED_SERVICE}.setup_router`.
To make life easier, by inheriting from WSF_URI_TEMPLATE_HELPER_FOR_ROUTED_SERVICE, a few help methods are available to `map` URI template with agent, and so on.
See
+ `map_uri_template (a_tpl: STRING; h: WSF_URI_TEMPLATE_HANDLER)`
+ `map_uri_template_agent (a_tpl: READABLE_STRING_8; proc: PROCEDURE [ANY, TUPLE [req: WSF_REQUEST; res: WSF_RESPONSE]])`
+ and same with request methods ...
...
Check WSF_\*_HELPER_FOR_ROUTED_SERVICE for other available helper classes.
How we do that in EWF? : Router with (or without context).
Related code: wsf_router, wsf_router_context
Examples
> [Learn more about router](Documentation__Router)
# EWF components
## URI Handler:
> Parses the details of the URI (scheme, path, query info, etc.) and exposes them for use.
How we do that in EWF?: URI Templates, but we could also use regex.
Related code: uri_template
Examples:
## Mime Parser/ Content Negotiation:
> Handles the details of determining the media type, language, encoding, compression (conneg).
How do we do that in EWF? Content_Negotiation library.
Example
## Request Handler
> target of request dispatcher + uri handler.
Here is where we handle GET, POST PUT, etc.
## Representation Mapping
> Converts stored data into the proper representation for responses and handles incoming representations from requests.
We dont have a representation library, the developer need to do that.
If we want to provide different kind of representations: JSON, XML, HTML, the responsibility is let
to the developer to map their domain to the target representation.
## Http Client:
> A simple library to make requests and handle responses from other http servers.
How we do that in EWF? http client library
examples:
## Authentication/Security:
> Handle different auth models. (Basic, Digest?, OAuth, OpenId)
How we do that in EWF? http_authorization, OpenId, and Cypress
examples.
## Caching:
> Support for Caching and conditional request
How we do that in Eiffel? Policy framework on top of EWF. {{{need_review}}}
examples
## EWF HTML5 Widgets
## EWF policy Framework
## EWF application generators
<a name="wiki-EWSGI"></a>
<a name="EWSGI"></a>
# EWSGI Specification
<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.
## server
* __ewsgi__: Eiffel Web Server Gateway Interface read more
* connectors: various web server connectors for EWSGI
* __libfcgi__: Wrapper for libfcgi SDK
* __wsf__: Web Server Framework [read more]
* __router__: URL dispatching/routing based on uri, uri_template, or custom read more
* __wsf_html__: (html and css) Content generator from the server side.
* CMS example: <https://github.com/EiffelWebFramework/cms/tree/master/example>
## protocol
* __http__: HTTP related classes, constants for status code, content types, ... read more
* __uri_template__: URI Template library (parsing and expander) read more
* __content_negotiation__: CONNEG library (Content-type Negociation) read more
## Client
* __http_client__: simple HTTP client based on cURL readmore
* __Firebase API__: <https://github.com/EiffelWebFramework/Redwood>
## Text
* __encoder__: Various simple encoders: base64, url-encoder, xml entities, html entities read more
## Utils
* __error__: very simple/basic library to handle error
## Security
* __http_authentication__ (under EWF/library/server/authentication)
* __open_id__ (under EWF/library/security)
* __OAuth__ see <https://github.com/EiffelWebFramework/cypress>

View File

@@ -0,0 +1 @@
See WSF_CONNECTOR

View File

@@ -0,0 +1,17 @@
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`

View File

@@ -0,0 +1 @@
See WSF_RESPONSE

View File

@@ -0,0 +1 @@
See WSF_ROUTER

View File

@@ -0,0 +1,2 @@
EWF Services
> See WSF\_SERVICE

View File

@@ -4,7 +4,7 @@
## Preface
This specification is a proposition based on recent discussion on the mailing list.
This is work in progress, so far nothing had been decided.
You can find another proposal at http://eiffel.seibostudios.se/wiki/EWSGI , it has common background and goal, however still differ on specific parts.
You can find another proposal at [http://eiffel.seibostudios.se/wiki/EWSGI](http://eiffel.seibostudios.se/wiki/EWSGI) , it has common background and goal, however still differ on specific parts.
The main goal for now is to unified those 2 specifications.
---
@@ -12,7 +12,7 @@ Note the following is work in progress, and reflect a specification proposal, ra
2011-08-01
---
For now, the specification from EWF is done in Eiffel interface
please see: https://github.com/Eiffel-World/Eiffel-Web-Framework/tree/master/library/server/ewsgi/specification
please see: [https://github.com/Eiffel-World/Eiffel-Web-Framework/tree/master/library/server/ewsgi/specification](https://github.com/Eiffel-World/Eiffel-Web-Framework/tree/master/library/server/ewsgi/specification)
WGI_APPLICATION

View File

@@ -1,5 +1,5 @@
- See proposed specifications: [[EWSGI specification| EWSGI-specification]]
- See [[Open questions| EWSGI-open-questions]]
- See proposed specifications: [EWSGI specification](./EWSGI-specification)
- See [Open questions](./EWSGI-Open-Questions)
- And below the various proposals and associated decision
----

27
doc/wiki/Filter.md Normal file
View File

@@ -0,0 +1,27 @@
# Introduction
The basic idea of a filter is to pre-process incoming data and post-process outgoing data.
Filters are part of a filter chain, thus following the [chain of responsability design pattern](http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern).
Each filter decides to call the next filter or not.
# Levels
In EWF, there are two levels of filters.
## WSF_FILTER
Typical examples of such filters are: logging, compression, routing (WSF_ROUTING_FILTER), ...
## WSF_FILTER_HANDLER
Handler that can also play the role of a filter.
Typical examples of such filters are: authentication, ...
# References
Filters (also called middelwares) in other environments:
* in Python: http://www.wsgi.org/en/latest/libraries.html
* in Node.js: http://expressjs.com/guide.html#middleware
* in Apache: http://httpd.apache.org/docs/2.2/en/filter.html

View File

@@ -1,26 +1,26 @@
# Eiffel-Web-Framework #
## Location ##
The official documentation/wiki is located at https://github.com/EiffelWebFramework/EWF/wiki , if you are visiting a "clone/fork", please always check the [[official wiki|https://github.com/EiffelWebFramework/EWF/wiki]].
The official documentation/wiki is located at [https://github.com/EiffelWebFramework/EWF/wiki](https://github.com/EiffelWebFramework/EWF/wiki) , if you are visiting a "clone/fork", please always check the [official wiki](https://github.com/EiffelWebFramework/EWF/wiki).
## Organization ##
- Mailing list: please visit and subscribe to the mailing list page [[http://groups.google.com/group/eiffel-web-framework]] ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif)
- Mailing list: please visit and subscribe to the mailing list page [http://groups.google.com/group/eiffel-web-framework](http://groups.google.com/group/eiffel-web-framework) ![logo](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif)
- Most of the topics are discussed on the mailing list (google group).
- For time to time we have [[web meetings|meetings]], and less frequently [[physical meetings|meetings]] that occurs usually during other Eiffel related events.
- For time to time we have [web meetings](./wiki/Meetings), and less frequently [physical meetings](./wiki/Meetings) that occurs usually during other Eiffel related events.
## Documentation ##
- to redo
- [Documentation](./Documentation)
## Contributions ##
- You want to contribute or follow the progress/discussion, see the [[collaboration page| Community-collaboration]]
- Potential tasks/projects on EWF: [[Projects page| Projects]]
- You want to contribute or follow the progress/discussion, see the [collaboration page](./wiki/Community-collaboration)
- Potential tasks/projects on EWF: [Projects page](./wiki/Projects)
## See also ##
- [[list of tasks, and a potential roadmap| Tasks-Roadmap]]
- [[General source structure of this project| Source-structure]]
- EWSGI: [[Eiffel Web Server Gateway Interface| EWSGI]]
- [[Overview of the server side architecture| Spec-Server-Architecture]]
- This project is also a collection of [[Libraries]] related to the Web
- [list of tasks, and a potential roadmap](./wiki/Tasks-Roadmap)
- [General source structure of this project](./wiki/Source-structure)
- EWSGI: [Eiffel Web Server Gateway Interface](./wiki/EWSGI)
- [Overview of the server side architecture](./wiki/Spec-Server-Architecture)
- This project is also a collection of [Libraries](./wiki/Libraries) related to the Web
## Note ##
- This wiki needs to be updated, in the meantime, please have a look at the presentation: https://docs.google.com/presentation/pub?id=1GPFv6aHhTjFSLMnlAt-J4WeIHSGfHdB42dQxmOVOH8s&start=false&loop=false&delayms=3000
- This wiki needs to be updated, in the meantime, please have a look at the presentation: [https://docs.google.com/presentation/pub?id=1GPFv6aHhTjFSLMnlAt-J4WeIHSGfHdB42dQxmOVOH8s&start=false&loop=false&delayms=3000](https://docs.google.com/presentation/pub?id=1GPFv6aHhTjFSLMnlAt-J4WeIHSGfHdB42dQxmOVOH8s&start=false&loop=false&delayms=3000)

View File

@@ -1,4 +1,4 @@
# Previous and future meetings
* [[Web-meeting: 2012-09-18|Web-meeting-2012-09-18]]
* [Web-meeting: 2012-09-18](./Web-meeting-2012-09-18)
* For previous meetings, check the ["meeting" topics](https://groups.google.com/forum/?fromgroups=#!tags/eiffel-web-framework/meeting) on the [forum](http://groups.google.com/group/eiffel-web-framework)

View File

@@ -1,5 +1,5 @@
Use this to suggest new projects, or request features.
The content of this page will be moved to the main [[Projects]] page for time to time.
The content of this page will be moved to the main [Projects](./Projects) page for time to time.
For any entry, please use this template
----
@@ -15,6 +15,6 @@ For any entry, please use this template
## Add support for Swagger
* _Suggested by **Olivier**_
* _Description_: Build a Swagger Eiffel implementation
* _References_: http://swagger.wordnik.com/
* _References_: [http://swagger.wordnik.com/](http://swagger.wordnik.com/)
----

View File

@@ -6,13 +6,13 @@ If you are a student, don't hesitate to pick one, or even suggest a new project,
## Evaluate EWF according to the following constraints ...
* _Suggested by **Javier**_
* _Description_: According to http://www.amundsen.com/blog/archives/1130 , evaluate the current design of EWF to see if this match the different points. An other option would be to take the following REST implementation toolkit as a guide to evaluate EWF http://code.google.com/p/implementing-rest/wiki/RESTImplementationToolkit.
* _Description_: According to [http://www.amundsen.com/blog/archives/1130](http://www.amundsen.com/blog/archives/1130) , evaluate the current design of EWF to see if this match the different points. An other option would be to take the following REST implementation toolkit as a guide to evaluate EWF [http://code.google.com/p/implementing-rest/wiki/RESTImplementationToolkit](http://code.google.com/p/implementing-rest/wiki/RESTImplementationToolkit).
## Road to Hypermedia API
* _Suggested by **Javier**_
* _Supervisor_:
* _Suitability_:
* _Description_: describe differents types of Web API, and how you can build them using EWF. Describing Pros and Cons. This should be on http://martinfowler.com/articles/richardsonMaturityModel.html
* _Description_: describe differents types of Web API, and how you can build them using EWF. Describing Pros and Cons. This should be on [http://martinfowler.com/articles/richardsonMaturityModel.html](http://martinfowler.com/articles/richardsonMaturityModel.html)
## Build a video to demonstrate how an Hypermedia API works, and how to build it using EWF
* _Suggested by **Javier**_
@@ -55,8 +55,8 @@ If you are a student, don't hesitate to pick one, or even suggest a new project,
* _Supervisor_:
* _Suitability_: TODO
* _Description_: EWF is relying on the notion of "connector" to achieve portability on various platform and underlying httpd server, currently EWF support any CGI or libFCGI system (i.e apache, IIS, ...), and provide a standalone version thanks to Eiffel Web Nino. The goal now, would be to support specific connector for:
** LightHTTP (http://www.lighttpd.net/)
** nginx (http://nginx.org/en/)
** LightHTTP ([http://www.lighttpd.net/](http://www.lighttpd.net/))
** nginx ([http://nginx.org/en/](http://nginx.org/en/))
## Concurrenty and EWF
* _Suggested by **Jocelyn**_
@@ -75,7 +75,7 @@ If you are a student, don't hesitate to pick one, or even suggest a new project,
* _Supervisor_:
* _Suitability_: TODO
* _Description_: Provide an implementation of websocket with EWF and eventually Eiffel Web Nino, then demonstrate it on a simple example. WebSocket is a web technology providing for bi-directional, full-duplex communications channels over a single TCP connection.
* See http://en.wikipedia.org/wiki/Websocket
* See [http://en.wikipedia.org/wiki/Websocket](http://en.wikipedia.org/wiki/Websocket)
----
# Usage of EWF
@@ -84,13 +84,13 @@ If you are a student, don't hesitate to pick one, or even suggest a new project,
* _Suggested by **Javier**_
* _Supervisor_:
* _Suitability_: TODO
* _Description_: Build a HAL browser to discover an API using HAL mediatype. The browser will be able to follow the links, and display the transmitted data. This could be a vision2 application inspired by http://haltalk.herokuapp.com/explorer/hal_browser.html#/. HAL stands for Hypertext Application Language see http://stateless.co/hal_specification.html.
* _Description_: Build a HAL browser to discover an API using HAL mediatype. The browser will be able to follow the links, and display the transmitted data. This could be a vision2 application inspired by [http://haltalk.herokuapp.com/explorer/hal_browser.html#/](http://haltalk.herokuapp.com/explorer/hal_browser.html#/). HAL stands for Hypertext Application Language see [http://stateless.co/hal_specification.html](http://stateless.co/hal_specification.html).
## Collection-JSON browser
* _Suggested by **Javier**_
* _Supervisor_:
* _Suitability_: TODO
* _Description_: Build a Collection/JSON browser to discover an API using Collection/JSON mediatype. The browser will be able to follow the links, and display the transmitted data. This could be a vision2 application inspired by http://haltalk.herokuapp.com/explorer/hal_browser.html#/. Collection+JSON is a JSON-based read/write hypermedia-type, see http://www.amundsen.com/media-types/collection/
* _Description_: Build a Collection/JSON browser to discover an API using Collection/JSON mediatype. The browser will be able to follow the links, and display the transmitted data. This could be a vision2 application inspired by [http://haltalk.herokuapp.com/explorer/hal_browser.html#/](http://haltalk.herokuapp.com/explorer/hal_browser.html#/). Collection+JSON is a JSON-based read/write hypermedia-type, see [http://www.amundsen.com/media-types/collection/](http://www.amundsen.com/media-types/collection/)
## Build a simple CMS with EWF
* _Suggested by **Jocelyn**_
@@ -119,7 +119,7 @@ If you are a student, don't hesitate to pick one, or even suggest a new project,
* _Suggested by **Javier**_
* _Supervisor_:
* _Suitability_: TODO
* _Description_: Use XHTML as a media type to for hypermedia API. See http://codeartisan.blogspot.com.ar/2012/07/using-html-as-media-type-for-your-api.html
* _Description_: Use XHTML as a media type to for hypermedia API. See [http://codeartisan.blogspot.com.ar/2012/07/using-html-as-media-type-for-your-api.html](http://codeartisan.blogspot.com.ar/2012/07/using-html-as-media-type-for-your-api.html)
## Add support for Mediatype such as RSS, ATOM, ...
* _Suggested by **Jocelyn**_
@@ -155,24 +155,24 @@ If you are a student, don't hesitate to pick one, or even suggest a new project,
* _Suitability_: TODO
* _Description_: Design and build a Single Sign On implementation for Eiffel. That should include the authentication server, and at least one Eiffel client component (it would be convenient to also provide php, js, ...). In the same spirit, having Eiffel client for popular SSO server would be appreciated as well.
* _Reference_:
- http://en.wikipedia.org/wiki/Single_sign-on
- http://en.wikipedia.org/wiki/List_of_single_sign-on_implementations
- [http://en.wikipedia.org/wiki/Single_sign-on](http://en.wikipedia.org/wiki/Single_sign-on)
- [http://en.wikipedia.org/wiki/List_of_single_sign-on_implementations](http://en.wikipedia.org/wiki/List_of_single_sign-on_implementations)
## library: Template engine
* _Suggested by **Jocelyn**_
* _Supervisor_:
* _Suitability_: TODO
* _Description_: Get inspired by any existing template engine, and build one for Eiffel, this should be easily usable within a web application. This could be inspired, or implementation of standard template engine, this way people can reuse existing content, or migrate easily their application to EWF. For inspiration, one can look at:
- http://www.smarty.net/
- http://mustache.github.com/
- http://en.wikipedia.org/wiki/Template_engine_(web) ... they are plenty of them, a comparison of the different engine would help.
- [http://www.smarty.net/](http://www.smarty.net/)
- [http://mustache.github.com/](http://mustache.github.com/)
- [http://en.wikipedia.org/wiki/Web_template_system](http://en.wikipedia.org/wiki/Web_template_system) ... they are plenty of them, a comparison of the different engine would help.
* This is not specific to EWF, but it will be very useful in website context.
## library: Wikitext, markdown parser and render engine
* _Suggested by **Jocelyn**_
* _Supervisor_:
* _Suitability_: TODO
* _Description_: Build component to support (read and write, and why not convert), lightweight markup language (see http://en.wikipedia.org/wiki/Lightweight_markup_language) such as wikitext, markdown, and other. The component should be able to read/scan, but also produce an HTML output. Focus first on wikitext, and markdown since they seems to be the most popular.
* _Description_: Build component to support (read and write, and why not convert), lightweight markup language (see [http://en.wikipedia.org/wiki/Lightweight_markup_language](http://en.wikipedia.org/wiki/Lightweight_markup_language)) such as wikitext, markdown, and other. The component should be able to read/scan, but also produce an HTML output. Focus first on wikitext, and markdown since they seems to be the most popular.
* Then , a nice addition would be to render those lightweight markup lang into Vision2 widget (not related to EWF, but could be useful to build (editor) desktop application)
## library: Web component to build HTML5 widget
@@ -195,16 +195,16 @@ If you are a student, don't hesitate to pick one, or even suggest a new project,
* _Suitability_: TODO
* _Description_: TODO
* Generic client that can be customized (see design in slide 12)
* http://s3.amazonaws.com/cimlabs/Oredev-Hypermedia-APIs.pdf
* video http://vimeo.com/20781278
* [http://s3.amazonaws.com/cimlabs/Oredev-Hypermedia-APIs.pdf](http://s3.amazonaws.com/cimlabs/Oredev-Hypermedia-APIs.pdf)
* video [http://vimeo.com/20781278](http://vimeo.com/20781278)
## Create a Client Cache based on Apache commons Client Cache.
* _Suggested by **Javier**_
* _Supervisor_:
* _Suitability_: TODO
* _Description_: TODO
* http://hc.apache.org/httpcomponents-client-ga/httpclient-cache/index.html
* http://labs.xfinity.com/benchmarking-the-httpclient-caching-module
* [http://hc.apache.org/httpcomponents-client-ga/httpclient-cache/index.html](http://hc.apache.org/httpcomponents-client-ga/httpclient-cache/index.html)
* [http://labs.xfinity.com/benchmarking-the-httpclient-caching-module](http://labs.xfinity.com/benchmarking-the-httpclient-caching-module)
## Add SSL support to Eiffel Net
* _Suggested by **Jocelyn**_
@@ -231,9 +231,9 @@ If you are a student, don't hesitate to pick one, or even suggest a new project,
* _Supervisor_:
* _Suitability_: TODO
* _Description_: TODO
* See: http://en.wikipedia.org/wiki/Edge_Side_Includes
* See: [http://en.wikipedia.org/wiki/Edge_Side_Includes](http://en.wikipedia.org/wiki/Edge_Side_Includes)
----
# Feel free to add new idea below this line
----
Use the following page [[Projects new suggestions]] to suggest new project, or request a feature.
Use the following page [Projects new suggestions](./Projects new suggestions) to suggest new project, or request a feature.

View File

@@ -0,0 +1,9 @@
# Request
The class _WSF_REQUEST_ can be used to access data related to the HTTP request.
**TODO**: describe the request interface
# Response
The class _WSF_RESPONSE_ is the media to send data back to the client.
**TODO**: describe the response interface

3
doc/wiki/Router.md Normal file
View File

@@ -0,0 +1,3 @@
The primary goal of the router (class _WSF_ROUTER_) is to dispatch requests according to the request URI.
**TODO**: describe the router interface

View File

@@ -1,3 +1,4 @@
Check new roadmap wiki page: [roadmap](./roadmap)
## Future
* Focus on REST API
- Hypermedia API
@@ -31,5 +32,5 @@
* Installation scripts
## Contributors ##
- See [[the collaboration page|Community-collaboration]]
- See [the collaboration page](./Community-collaboration)

View File

@@ -1,14 +1,14 @@
## Eiffel
* http://www.scoop.it/t/eiffel-resources
* http://www.scoop.it/t/eiffel
* [http://www.scoop.it/t/eiffel-resources](http://www.scoop.it/t/eiffel-resources)
* [http://www.scoop.it/t/eiffel](http://www.scoop.it/t/eiffel)
## Hypermedia
* http://www.scoop.it/t/hyper-media-apis
* http://www.scoop.it/t/hypermedia-api
* [http://www.scoop.it/t/hyper-media-apis](http://www.scoop.it/t/hyper-media-apis)
* [http://www.scoop.it/t/hypermedia-api](http://www.scoop.it/t/hypermedia-api)
## ETags
* http://www.mnot.net/blog/2007/08/07/etags
* http://bitworking.org/news/150/REST-Tip-Deep-etags-give-you-more-benefits
* [http://www.mnot.net/blog/2007/08/07/etags](http://www.mnot.net/blog/2007/08/07/etags)
* [http://bitworking.org/news/150/REST-Tip-Deep-etags-give-you-more-benefits](http://bitworking.org/news/150/REST-Tip-Deep-etags-give-you-more-benefits)

View File

@@ -1,7 +1,5 @@
# Using the policy driven framework
**This describes a new facility that is not yet in the EWF release**
## Introduction
The aim of the policy-driven framework is to allow authors of web-servers to concentrate on the business logic (e.g., in the case of a GET request, generating the content), without having to worry about the details of the HTTP protocol (such as headers and response codes). However, there are so many possibilities in the HTTP protocol, that it is impossible to correctly guess what to do in all cases. Therefore the author has to supply policy decisions to the framework, in areas such as caching decisions. These are implemented as a set of deferred classes for which the author needs to provide effective implementations.

View File

@@ -8,14 +8,14 @@
## Information
### When ?
* Tuesday 18th of september, 19:00 - 20:00 UTC/GMT time (see 3rd time in http://www.doodle.com/8v2sekiyebp4dpyh)
* Tuesday 18th of september, 19:00 - 20:00 UTC/GMT time (see 3rd time in [http://www.doodle.com/8v2sekiyebp4dpyh](http://www.doodle.com/8v2sekiyebp4dpyh))
### Where ?
Web meeting using webex
* Short url: http://goo.gl/wBz11
* Long url: https://eiffel.webex.com/eiffel/j.php?ED=211265702&UID=0&PW=NZWNiMjBiZWIz&RT=MiMyMA%3D%3D
* Related Google group topic: https://groups.google.com/d/topic/eiffel-web-framework/A7ADPAT3nj8/discussion
* Short url: [http://goo.gl/wBz11](http://goo.gl/wBz11)
* Long url: [https://eiffel.webex.com/eiffel/j.php?ED=211265702&UID=0&PW=NZWNiMjBiZWIz&RT=MiMyMA%3D%3D](https://eiffel.webex.com/eiffel/j.php?ED=211265702&UID=0&PW=NZWNiMjBiZWIz&RT=MiMyMA%3D%3D)
* Related Google group topic: [https://groups.google.com/d/topic/eiffel-web-framework/A7ADPAT3nj8/discussion](https://groups.google.com/d/topic/eiffel-web-framework/A7ADPAT3nj8/discussion)
## Agenda

4
doc/wiki/roadmap.md Normal file
View File

@@ -0,0 +1,4 @@
# Upcoming versions
# Current state: oct-2013
- check previous wiki page: [Tasks roadmap](./Tasks roadmap)

View File

@@ -1,3 +1,4 @@
The gewf tool, is an experimentation to generate EWF project from template.
status: experimental, POC, in-progress, draft

View File

@@ -10,6 +10,7 @@
</file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="transitional" syntax="standard">
</option>
<setting name="console_application" value="true"/>
<setting name="executable_name" value="gewf"/>
<setting name="concurrency" value="none"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>

View File

@@ -18,6 +18,8 @@ feature {NONE} -- Initialization
args: ARGUMENTS_32
cfg: detachable READABLE_STRING_32
do
create setup.make
create args
if args.argument_count > 0 then
cfg := args.argument (1)
@@ -28,13 +30,11 @@ feature {NONE} -- Initialization
execute
end
feature -- Status
setup: GEWF_SETUP
feature -- Access
config (k: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
local
l_keys: LIST [READABLE_STRING_GENERAL]
do
if attached {JSON_STRING} json_item (json, k) as js then
Result := js.unescaped_string_32
@@ -95,6 +95,9 @@ feature -- Access
create p.make_parser (s)
json := p.parse
if attached config ("gewf.template_dir") as d then
setup.set_template_dir_from_string (d)
end
end
json: detachable JSON_VALUE
@@ -141,8 +144,7 @@ feature -- Execution
p: PATH
appname: detachable READABLE_STRING_GENERAL
do
create p.make_from_string ("template")
p := p.extended (tpl)
p := setup.template_dir.extended (tpl)
appname := vals.item ("APPNAME")
if appname = Void then
appname := "_generated"

View File

@@ -0,0 +1,109 @@
note
description: "[
Configuration of GEWF tool.
]"
date: "$Date$"
revision: "$Revision$"
class
GEWF_SETUP
inherit
SHARED_EXECUTION_ENVIRONMENT
create
make
feature -- Initialization
make
do
--| root_dir
get_root_dir
--| template_dir
get_template_dir
end
get_root_dir
local
ut: FILE_UTILITIES
p: detachable PATH
do
--| either $GEWF, or $HOME/.gewf or cwd/.gewf or cwd
if attached execution_environment.item ("GEWF") as s then
create p.make_from_string (s)
elseif attached execution_environment.item ("HOME") as s then
create p.make_from_string (s)
p := p.extended (".gewf")
create ut
if not ut.directory_path_exists (p) then
p := Void
end
end
if p = Void then
p := execution_environment.current_working_path
if ut.directory_path_exists (p.extended (".gewf")) then
p := p.extended (".gewf")
end
end
root_dir := p
end
get_template_dir
do
if attached execution_environment.item ("GEWF_TEMPLATE_DIR") as tpl_dir then
create template_dir.make_from_string (tpl_dir)
else
template_dir := root_dir.extended ("template")
end
end
feature -- Access
root_dir: PATH
template_dir: PATH
feature -- Status report
is_custom_template_dir: BOOLEAN
is_custom_root_dir: BOOLEAN
feature -- Change
set_root_dir (p: PATH)
do
is_custom_root_dir := True
root_dir := p
if not is_custom_template_dir then
-- update template_dir
get_template_dir
end
end
set_template_dir_from_string (dn: READABLE_STRING_GENERAL)
do
set_template_dir (create {PATH} .make_from_string (dn))
end
set_template_dir (p: PATH)
do
is_custom_template_dir := True
template_dir := p
end
;note
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Olivier Ligot, 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

View File

@@ -1,85 +1,18 @@
note
description: "Summary description for {APPLICATION_LAUNCHER}."
author: ""
description: "[
Effective class for APPLICATION_LAUNCHER_I
You can put modification in this class
]"
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
revision: "$Revision: 36 $"
deferred class
class
APPLICATION_LAUNCHER
feature {NONE} -- Initialization
inherit
APPLICATION_LAUNCHER_I
launcher_nature: detachable READABLE_STRING_8
-- Initialize the launcher nature
-- either cgi, libfcgi, or nino.
--| We could extend with more connector if needed.
--| and we could use WSF_DEFAULT_SERVICE_LAUNCHER to configure this at compilation time.
local
p: PATH
l_entry_name: READABLE_STRING_32
ext: detachable READABLE_STRING_32
do
create p.make_from_string (execution_environment.arguments.command_name)
if attached p.entry as l_entry then
ext := l_entry.extension
end
if ext /= Void then
if ext.same_string (nature_nino) then
Result := nature_nino
end
if ext.same_string (nature_cgi) then
Result := nature_cgi
end
if ext.same_string (nature_libfcgi) or else ext.same_string ("fcgi") then
Result := nature_libfcgi
end
end
end
feature {NONE} -- nino
nature_nino: STRING = "nino"
launch_nino (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
do
create {WSF_NINO_SERVICE_LAUNCHER} launcher.make_and_launch (a_service, opts)
end
feature {NONE} -- cgi
nature_cgi: STRING = "cgi"
launch_cgi (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
do
create {WSF_CGI_SERVICE_LAUNCHER} launcher.make_and_launch (a_service, opts)
end
feature {NONE} -- libfcgi
nature_libfcgi: STRING = "libfcgi"
launch_libfcgi (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
do
create {WSF_LIBFCGI_SERVICE_LAUNCHER} launcher.make_and_launch (a_service, opts)
end
feature {NONE} -- Launcher
launch (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
nature: like launcher_nature
do
nature := launcher_nature
if nature = Void or else nature = nature_nino then
launch_nino (a_service, opts)
elseif nature = nature_cgi then
launch_cgi (a_service, opts)
elseif nature = nature_libfcgi then
launch_libfcgi (a_service, opts)
else
-- bye bye
(create {EXCEPTIONS}).die (-1)
end
end
feature -- Custom
end

View File

@@ -0,0 +1,101 @@
note
description: "[
Specific application launcher
DO NOT EDIT THIS CLASS
you can customize APPLICATION_LAUNCHER
]"
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
revision: "$Revision: 36 $"
deferred class
APPLICATION_LAUNCHER_I
inherit
SHARED_EXECUTION_ENVIRONMENT
feature -- Execution
launch (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
nature: like launcher_nature
do
nature := launcher_nature
if nature = Void or else nature = nature_nino then
launch_nino (a_service, opts)
elseif nature = nature_cgi then
launch_cgi (a_service, opts)
elseif nature = nature_libfcgi then
launch_libfcgi (a_service, opts)
else
-- bye bye
(create {EXCEPTIONS}).die (-1)
end
end
feature {NONE} -- Access
launcher_nature: detachable READABLE_STRING_8
-- Initialize the launcher nature
-- either cgi, libfcgi, or nino.
--| We could extend with more connector if needed.
--| and we could use WSF_DEFAULT_SERVICE_LAUNCHER to configure this at compilation time.
local
p: PATH
l_entry_name: READABLE_STRING_32
ext: detachable READABLE_STRING_32
do
create p.make_from_string (execution_environment.arguments.command_name)
if attached p.entry as l_entry then
ext := l_entry.extension
end
if ext /= Void then
if ext.same_string (nature_nino) then
Result := nature_nino
end
if ext.same_string (nature_cgi) then
Result := nature_cgi
end
if ext.same_string (nature_libfcgi) or else ext.same_string ("fcgi") then
Result := nature_libfcgi
end
end
end
feature {NONE} -- nino
nature_nino: STRING = "nino"
launch_nino (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_NINO_SERVICE_LAUNCHER
do
create launcher.make_and_launch (a_service, opts)
end
feature {NONE} -- cgi
nature_cgi: STRING = "cgi"
launch_cgi (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_CGI_SERVICE_LAUNCHER
do
create launcher.make_and_launch (a_service, opts)
end
feature {NONE} -- libfcgi
nature_libfcgi: STRING = "libfcgi"
launch_libfcgi (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_LIBFCGI_SERVICE_LAUNCHER
do
create launcher.make_and_launch (a_service, opts)
end
end

View File

@@ -1,19 +1,18 @@
note
description: "Summary description for {APPLICATION}."
author: ""
description: "[
Effective class for APPLICATION_LAUNCHER_I
You can put modification in this class
]"
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
revision: "$Revision: 36 $"
deferred class
class
APPLICATION_LAUNCHER
feature {NONE} -- Launcher
inherit
APPLICATION_LAUNCHER_I
launch (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_SERVICE_LAUNCHER
do
create {WSF_DEFAULT_SERVICE_LAUNCHER} launcher.make_and_launch (a_service, opts)
end
feature -- Custom
end

View File

@@ -0,0 +1,25 @@
note
description: "[
Specific application launcher
DO NOT EDIT THIS CLASS
you can customize APPLICATION_LAUNCHER
]"
date: "$Date: 2013-06-12 13:55:42 +0200 (mer., 12 juin 2013) $"
revision: "$Revision: 36 $"
deferred class
APPLICATION_LAUNCHER_I
feature -- Execution
launch (a_service: WSF_SERVICE; opts: detachable WSF_SERVICE_LAUNCHER_OPTIONS)
local
launcher: WSF_SERVICE_LAUNCHER
do
create {WSF_DEFAULT_SERVICE_LAUNCHER} launcher.make_and_launch (a_service, opts)
end
end

View File

@@ -0,0 +1,2 @@
This example demonstrates the use of embedded Vision2 web browser component, and embedded EWF server (using nino).

View 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>

View File

@@ -0,0 +1 @@
Test

View 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>

View 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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -21,10 +21,14 @@ feature -- Basic operations
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute the filter
local
l_auth: HTTP_AUTHORIZATION
l_auth: detachable HTTP_AUTHORIZATION
do
create l_auth.make (req.http_authorization)
if (attached l_auth.type as l_auth_type and then l_auth_type.is_equal ("basic")) and
if attached req.http_authorization as l_http_authorization then
create l_auth.make (l_http_authorization)
end
if
l_auth /= Void and then
(attached l_auth.type as l_auth_type and then l_auth_type.same_string ("basic")) and then
attached l_auth.login as l_auth_login and then
attached Db_access.user (0, l_auth_login) as l_user and then
l_auth_login.same_string (l_user.name) and then

View File

@@ -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"/>

View File

@@ -155,6 +155,9 @@ Response success
} ]
}
note:
curl -vv http://localhost:9090/order -H "Content-Type: application/json" -d "{\"location\":\"takeAway\",\"items\":[{\"name\":\"Late\",\"option\":\"skim\",\"size\":\"Small\",\"quantity\":1}]}" -X POST
How to Read an order with GET
-----------------------------
@@ -192,7 +195,8 @@ Response
} ]
}
note:
curl -vv http://localhost:9090/order/1
How to Update an order with PUT
-------------------------------

View File

@@ -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">
@@ -13,9 +15,9 @@
<debug name="nino" enabled="true"/>
</option>
</library>
<library name="conneg" location="..\..\library\network\protocol\CONNEG\conneg-safe.ecf"/>
<library name="conneg" location="..\..\library\network\protocol\content_negotiation\conneg-safe.ecf"/>
<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="eel" location="$ISE_LIBRARY\contrib\library\text\encryption\eel\eel-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>

View File

@@ -65,7 +65,7 @@ feature -- Access
-- At present, there is no support for this except for DELETE.
end
conneg (req: WSF_REQUEST): CONNEG_SERVER_SIDE
conneg (req: WSF_REQUEST): SERVER_CONTENT_NEGOTIATION
-- Content negotiatior for all requests
once
create Result.make ({HTTP_MIME_TYPES}.application_json, "en", "UTF-8", "identity")
@@ -227,8 +227,7 @@ feature -- Execution
end
end
ensure then
order_saved_only_for_get_head: req.is_get_head_request_method =
attached {ORDER} req.execution_variable (Order_execution_variable)
order_saved_only_for_get_head: attached {ORDER} req.execution_variable (Order_execution_variable) implies req.is_get_head_request_method
end
feature -- GET/HEAD content

View File

@@ -6,28 +6,19 @@ note
class
ETAG_UTILS
inherit
ARRAY_FACILITIES
feature -- Access
md5_digest (a_string: STRING): STRING
-- Cryptographic hash function that produces a 128-bit (16-byte) hash value, based on `a_string'
local
md5: MD5
output: SPECIAL [NATURAL_8]
do
create md5.make
create output.make_filled (0, 16)
md5.sink_string (a_string)
md5.do_final (output, 0)
Result := as_natural_32_be (output, 0).to_hex_string
Result.append (as_natural_32_be (output, 4).to_hex_string)
Result.append (as_natural_32_be (output, 8).to_hex_string)
Result.append (as_natural_32_be (output, 12).to_hex_string)
md5.update_from_string (a_string)
Result := md5.digest_as_string
end
note
copyright: "2011-2012, Javier Velilla and others"
copyright: "2011-2014, Javier Velilla and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -43,6 +43,7 @@ feature {NONE} -- Initialization
local
www: WSF_FILE_SYSTEM_HANDLER
do
map_uri_template_agent_with_request_methods ("/upload/{name}{?nb}", agent execute_upload_put, router.methods_put)
map_uri_template_agent ("/upload{?nb}", agent execute_upload)
create www.make (document_root)
@@ -95,7 +96,7 @@ feature -- Execution
local
l_body: STRING_8
l_safe_filename: STRING_8
fn: FILE_NAME
fn: PATH
page: WSF_HTML_PAGE_RESPONSE
n: INTEGER
do
@@ -114,8 +115,8 @@ feature -- Execution
end
if attached {WSF_STRING} req.query_parameter ("demo") as p_demo then
create fn.make_from_string (document_root)
fn.set_file_name (p_demo.value)
l_body.append ("File: <input type=%"file%" name=%"uploaded_file[]%" size=%"60%" value=%""+ html_encode (fn.string) +"%"></br>%N")
fn := fn.extended (p_demo.value)
l_body.append ("File: <input type=%"file%" name=%"uploaded_file[]%" size=%"60%" value=%""+ html_encode (fn.name) +"%"></br>%N")
end
from
@@ -131,15 +132,17 @@ feature -- Execution
create l_body.make (255)
l_body.append ("<h1>EWF: Uploaded files</h1>%N")
l_body.append ("<ul>")
n := 0
across
req.uploaded_files as c
loop
n := n + 1
l_body.append ("<li>")
l_body.append ("<div>" + c.item.name + "=" + html_encode (c.item.filename) + " size=" + c.item.size.out + " type=" + c.item.content_type + "</div>")
create fn.make_from_string (files_root)
l_safe_filename := c.item.safe_filename
fn.set_file_name (l_safe_filename)
if c.item.move_to (fn.string) then
fn := fn.extended (l_safe_filename)
if c.item.move_to (fn.name) then
if c.item.content_type.starts_with ("image") then
l_body.append ("%N<a href=%"../files/" + url_encode (l_safe_filename) + "%"><img src=%"../files/"+ l_safe_filename +"%" /></a>")
else
@@ -148,6 +151,7 @@ feature -- Execution
end
l_body.append ("</li>")
end
l_body.append ("</ul>")
create page.make
@@ -158,8 +162,85 @@ feature -- Execution
end
end
execute_upload_put (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Upload page is requested, PUT
require
is_put_request_method: req.is_put_request_method
local
l_body: STRING_8
l_safe_filename: detachable READABLE_STRING_32
fn: PATH
page: WSF_HTML_PAGE_RESPONSE
n: INTEGER
do
create l_body.make (255)
l_body.append ("<h1>EWF: Uploaded files</h1>%N")
l_body.append ("<ul>")
n := 0
if attached {WSF_STRING} req.path_parameter ("name") as p_name then
l_safe_filename := p_name.value
end
if l_safe_filename = Void or else l_safe_filename.is_empty then
l_safe_filename := "input_data"
end
if n = 0 and req.content_length_value > 0 then
if attached new_temporary_output_file ("tmp-uploaded-file_" + n.out) as f then
req.read_input_data_into_file (f)
f.close
create fn.make_from_string (files_root)
fn := fn.extended (l_safe_filename)
f.rename_file (fn.name)
l_body.append ("<li>")
l_body.append ("<div>Input data : size=" + f.count.out + " (" + req.content_length_value.out + ")</div>")
l_body.append ("%N<a href=%"../files/" + url_encode (l_safe_filename) + "%">"+ html_encode (l_safe_filename) +"</a>")
l_body.append ("</li>")
end
end
l_body.append ("</ul>")
create page.make
page.set_title ("EWF: uploaded image")
page.add_style ("../style.css", "all")
page.set_body (l_body)
res.send (page)
end
feature {NONE} -- Encoder
new_temporary_output_file (n: detachable READABLE_STRING_8): detachable FILE
local
bp: detachable PATH
d: DIRECTORY
i: INTEGER
do
create bp.make_current
create d.make_with_path (bp)
if not d.exists then
d.recursive_create_dir
end
if n /= Void then
bp := bp.extended ("tmp-download-" + n)
else
bp := bp.extended ("tmp")
end
from
i := 0
until
Result /= Void or i > 100
loop
i := i + 1
create {RAW_FILE} Result.make_with_path (bp.appended ("__" + i.out))
if Result.exists then
Result := Void
else
Result.open_write
end
end
ensure
Result /= Void implies Result.is_open_write
end
url_encode (s: READABLE_STRING_32): STRING_8
-- URL Encode `s' as Result
do

View File

@@ -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>

View File

@@ -1,51 +1,62 @@
# Available libraries.
http_client-safe : c:\_dev\EWF\EWF-dev\library\network\http_client\http_client-safe.ecf
http_client : c:\_dev\EWF\EWF-dev\library\network\http_client\http_client.ecf
conneg-safe : c:\_dev\EWF\EWF-dev\library\network\protocol\CONNEG\conneg-safe.ecf
conneg : c:\_dev\EWF\EWF-dev\library\network\protocol\CONNEG\conneg.ecf
http-safe : c:\_dev\EWF\EWF-dev\library\network\protocol\http\http-safe.ecf
http : c:\_dev\EWF\EWF-dev\library\network\protocol\http\http.ecf
http_authorization-safe : c:\_dev\EWF\EWF-dev\library\server\authentication\http_authorization\http_authorization-safe.ecf
http_authorization : c:\_dev\EWF\EWF-dev\library\server\authentication\http_authorization\http_authorization.ecf
ewsgi-safe : c:\_dev\EWF\EWF-dev\library\server\ewsgi\ewsgi-safe.ecf
ewsgi : c:\_dev\EWF\EWF-dev\library\server\ewsgi\ewsgi.ecf
ewsgi_spec-safe : c:\_dev\EWF\EWF-dev\library\server\ewsgi\ewsgi_spec-safe.ecf
ewsgi_spec : c:\_dev\EWF\EWF-dev\library\server\ewsgi\ewsgi_spec.ecf
cgi-safe : c:\_dev\EWF\EWF-dev\library\server\ewsgi\connectors\cgi\cgi-safe.ecf
cgi : c:\_dev\EWF\EWF-dev\library\server\ewsgi\connectors\cgi\cgi.ecf
libfcgi-safe : c:\_dev\EWF\EWF-dev\library\server\ewsgi\connectors\libfcgi\libfcgi-safe.ecf
libfcgi : c:\_dev\EWF\EWF-dev\library\server\ewsgi\connectors\libfcgi\libfcgi.ecf
nino-safe : c:\_dev\EWF\EWF-dev\library\server\ewsgi\connectors\nino\nino-safe.ecf
nino : c:\_dev\EWF\EWF-dev\library\server\ewsgi\connectors\nino\nino.ecf
null-safe : c:\_dev\EWF\EWF-dev\library\server\ewsgi\connectors\null\null-safe.ecf
null : c:\_dev\EWF\EWF-dev\library\server\ewsgi\connectors\null\null.ecf
fcgi-safe : c:\_dev\EWF\EWF-dev\library\server\libfcgi\fcgi-safe.ecf
fcgi : c:\_dev\EWF\EWF-dev\library\server\libfcgi\fcgi.ecf
libfcgi-safe : c:\_dev\EWF\EWF-dev\library\server\libfcgi\libfcgi-safe.ecf
libfcgi : c:\_dev\EWF\EWF-dev\library\server\libfcgi\libfcgi.ecf
router-safe : c:\_dev\EWF\EWF-dev\library\server\request\router\router-safe.ecf
router : c:\_dev\EWF\EWF-dev\library\server\request\router\router.ecf
wsf-safe : c:\_dev\EWF\EWF-dev\library\server\wsf\wsf-safe.ecf
wsf : c:\_dev\EWF\EWF-dev\library\server\wsf\wsf.ecf
all-safe : c:\_dev\EWF\EWF-dev\library\server\wsf\connector\all-safe.ecf
cgi-safe : c:\_dev\EWF\EWF-dev\library\server\wsf\connector\cgi-safe.ecf
cgi : c:\_dev\EWF\EWF-dev\library\server\wsf\connector\cgi.ecf
libfcgi-safe : c:\_dev\EWF\EWF-dev\library\server\wsf\connector\libfcgi-safe.ecf
libfcgi : c:\_dev\EWF\EWF-dev\library\server\wsf\connector\libfcgi.ecf
nino-safe : c:\_dev\EWF\EWF-dev\library\server\wsf\connector\nino-safe.ecf
nino : c:\_dev\EWF\EWF-dev\library\server\wsf\connector\nino.ecf
cgi-safe : c:\_dev\EWF\EWF-dev\library\server\wsf\default\cgi-safe.ecf
cgi : c:\_dev\EWF\EWF-dev\library\server\wsf\default\cgi.ecf
libfcgi-safe : c:\_dev\EWF\EWF-dev\library\server\wsf\default\libfcgi-safe.ecf
libfcgi : c:\_dev\EWF\EWF-dev\library\server\wsf\default\libfcgi.ecf
nino-safe : c:\_dev\EWF\EWF-dev\library\server\wsf\default\nino-safe.ecf
nino : c:\_dev\EWF\EWF-dev\library\server\wsf\default\nino.ecf
wsf_extension-safe : c:\_dev\EWF\EWF-dev\library\server\wsf_extension\wsf_extension-safe.ecf
wsf_extension : c:\_dev\EWF\EWF-dev\library\server\wsf_extension\wsf_extension.ecf
encoder-safe : c:\_dev\EWF\EWF-dev\library\text\encoder\encoder-safe.ecf
encoder : c:\_dev\EWF\EWF-dev\library\text\encoder\encoder.ecf
error-safe : c:\_dev\EWF\EWF-dev\library\utility\general\error\error-safe.ecf
error : c:\_dev\EWF\EWF-dev\library\utility\general\error\error.ecf
http_client-safe : C:\_dev\projects\ewf\ewf\library\network\http_client\http_client-safe.ecf
http_client : C:\_dev\projects\ewf\ewf\library\network\http_client\http_client.ecf
conneg-safe : C:\_dev\projects\ewf\ewf\library\network\protocol\content_negotiation\conneg-safe.ecf
conneg : C:\_dev\projects\ewf\ewf\library\network\protocol\content_negotiation\conneg.ecf
http-safe : C:\_dev\projects\ewf\ewf\library\network\protocol\http\http-safe.ecf
http : C:\_dev\projects\ewf\ewf\library\network\protocol\http\http.ecf
notification_email-safe : C:\_dev\projects\ewf\ewf\library\runtime\process\notification_email\notification_email-safe.ecf
notification_email : C:\_dev\projects\ewf\ewf\library\runtime\process\notification_email\notification_email.ecf
openid-safe : C:\_dev\projects\ewf\ewf\library\security\openid\consumer\openid-safe.ecf
openid : C:\_dev\projects\ewf\ewf\library\security\openid\consumer\openid.ecf
demo-safe : C:\_dev\projects\ewf\ewf\library\security\openid\consumer\demo\demo-safe.ecf
http_authorization-safe : C:\_dev\projects\ewf\ewf\library\server\authentication\http_authorization\http_authorization-safe.ecf
http_authorization : C:\_dev\projects\ewf\ewf\library\server\authentication\http_authorization\http_authorization.ecf
ewsgi-safe : C:\_dev\projects\ewf\ewf\library\server\ewsgi\ewsgi-safe.ecf
ewsgi : C:\_dev\projects\ewf\ewf\library\server\ewsgi\ewsgi.ecf
ewsgi_spec-safe : C:\_dev\projects\ewf\ewf\library\server\ewsgi\ewsgi_spec-safe.ecf
ewsgi_spec : C:\_dev\projects\ewf\ewf\library\server\ewsgi\ewsgi_spec.ecf
cgi-safe : C:\_dev\projects\ewf\ewf\library\server\ewsgi\connectors\cgi\cgi-safe.ecf
cgi : C:\_dev\projects\ewf\ewf\library\server\ewsgi\connectors\cgi\cgi.ecf
libfcgi-safe : C:\_dev\projects\ewf\ewf\library\server\ewsgi\connectors\libfcgi\libfcgi-safe.ecf
libfcgi : C:\_dev\projects\ewf\ewf\library\server\ewsgi\connectors\libfcgi\libfcgi.ecf
nino-safe : C:\_dev\projects\ewf\ewf\library\server\ewsgi\connectors\nino\nino-safe.ecf
nino : C:\_dev\projects\ewf\ewf\library\server\ewsgi\connectors\nino\nino.ecf
null-safe : C:\_dev\projects\ewf\ewf\library\server\ewsgi\connectors\null\null-safe.ecf
null : C:\_dev\projects\ewf\ewf\library\server\ewsgi\connectors\null\null.ecf
libfcgi-safe : C:\_dev\projects\ewf\ewf\library\server\libfcgi\libfcgi-safe.ecf
libfcgi : C:\_dev\projects\ewf\ewf\library\server\libfcgi\libfcgi.ecf
wsf-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\wsf-safe.ecf
wsf : C:\_dev\projects\ewf\ewf\library\server\wsf\wsf.ecf
wsf_extension-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\wsf_extension-safe.ecf
wsf_extension : C:\_dev\projects\ewf\ewf\library\server\wsf\wsf_extension.ecf
wsf_policy_driven-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\wsf_policy_driven-safe.ecf
wsf_policy_driven : C:\_dev\projects\ewf\ewf\library\server\wsf\wsf_policy_driven.ecf
wsf_router_context-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\wsf_router_context-safe.ecf
wsf_router_context : C:\_dev\projects\ewf\ewf\library\server\wsf\wsf_router_context.ecf
wsf_session-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\wsf_session-safe.ecf
wsf_session : C:\_dev\projects\ewf\ewf\library\server\wsf\wsf_session.ecf
all-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\connector\all-safe.ecf
cgi-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\connector\cgi-safe.ecf
cgi : C:\_dev\projects\ewf\ewf\library\server\wsf\connector\cgi.ecf
libfcgi-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\connector\libfcgi-safe.ecf
libfcgi : C:\_dev\projects\ewf\ewf\library\server\wsf\connector\libfcgi.ecf
nino-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\connector\nino-safe.ecf
nino : C:\_dev\projects\ewf\ewf\library\server\wsf\connector\nino.ecf
openshift-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\connector\openshift-safe.ecf
cgi-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\default\cgi-safe.ecf
cgi : C:\_dev\projects\ewf\ewf\library\server\wsf\default\cgi.ecf
libfcgi-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\default\libfcgi-safe.ecf
libfcgi : C:\_dev\projects\ewf\ewf\library\server\wsf\default\libfcgi.ecf
nino-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\default\nino-safe.ecf
nino : C:\_dev\projects\ewf\ewf\library\server\wsf\default\nino.ecf
openshift-safe : C:\_dev\projects\ewf\ewf\library\server\wsf\default\openshift-safe.ecf
wsf_html-safe : C:\_dev\projects\ewf\ewf\library\server\wsf_html\wsf_html-safe.ecf
wsf_html : C:\_dev\projects\ewf\ewf\library\server\wsf_html\wsf_html.ecf
encoder-safe : C:\_dev\projects\ewf\ewf\library\text\encoder\encoder-safe.ecf
encoder : C:\_dev\projects\ewf\ewf\library\text\encoder\encoder.ecf
error-safe : C:\_dev\projects\ewf\ewf\library\utility\general\error\error-safe.ecf
error : C:\_dev\projects\ewf\ewf\library\utility\general\error\error.ecf

View File

@@ -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>
@@ -10,16 +10,7 @@
<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="curl" location="$ISE_LIBRARY\library\cURL\cURL-safe.ecf">
<condition>
<version type="compiler" min="7.1.8.8674"/>
</condition>
</library>
<library name="curl_local" location="..\..\..\contrib\ise_library\cURL-safe.ecf">
<condition>
<version type="compiler" max="7.1.8.8673"/>
</condition>
</library>
<library name="curl" location="$ISE_LIBRARY\library\cURL\cURL-safe.ecf"/>
<library name="encoder" location="..\..\text\encoder\encoder-safe.ecf"/>
<library name="net" location="$ISE_LIBRARY\library\net\net-safe.ecf"/>
<cluster name="src" location=".\src\" recursive="true"/>

View File

@@ -11,16 +11,7 @@
</option>
<library name="base" location="$ISE_LIBRARY/library/base/base.ecf"/>
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
<library name="curl" location="$ISE_LIBRARY\library\cURL\cURL.ecf">
<condition>
<version type="compiler" min="7.1.8.8674"/>
</condition>
</library>
<library name="curl_local" location="..\..\..\contrib\ise_library\cURL.ecf">
<condition>
<version type="compiler" max="7.1.8.8673"/>
</condition>
</library>
<library name="curl" location="$ISE_LIBRARY\library\cURL\cURL.ecf"/>
<library name="encoder" location="../../text/encoder/encoder.ecf"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>

View 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

View File

@@ -111,12 +111,14 @@ feature -- Settings
timeout: INTEGER
-- HTTP transaction timeout in seconds.
--| 0 means it nevers timeout
do
Result := session.timeout
end
connect_timeout: INTEGER
-- HTTP connection timeout in seconds.
--| 0 means it nevers timeout
do
Result := session.connect_timeout
end
@@ -218,7 +220,7 @@ feature {NONE} -- Utilities: encoding
end
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -5,7 +5,7 @@ note
- headers
- query_parameters
- form parameters
- upload_data or upload_filename
- upload_data xor upload_filename
And in addition it has
- credentials_required
- proxy
@@ -86,16 +86,20 @@ feature -- Access
feature -- Status report
has_form_data: BOOLEAN
-- Has any form parameters?
--| i.e coming from POST or PUT content.
do
Result := not form_parameters.is_empty
end
has_upload_data: BOOLEAN
-- Has associated upload_data?
do
Result := attached upload_data as d and then not d.is_empty
end
has_upload_filename: BOOLEAN
-- Has associated upload_filename?
do
Result := attached upload_filename as fn and then not fn.is_empty
end
@@ -109,11 +113,13 @@ feature -- Status report
feature -- Element change
add_header (k: READABLE_STRING_8; v: READABLE_STRING_8)
-- Add http header line `k:v'.
do
headers.force (v, k)
end
add_header_line (s: READABLE_STRING_8)
-- Add http header line `s'.
local
i: INTEGER
do
@@ -124,6 +130,7 @@ feature -- Element change
end
add_header_lines (lst: ITERABLE [READABLE_STRING_8])
-- Add collection of http header lines `lst'
do
across
lst as c
@@ -133,44 +140,61 @@ feature -- Element change
end
add_query_parameter (k: READABLE_STRING_32; v: READABLE_STRING_32)
-- Add a query parameter `k=v'.
do
query_parameters.force (v, k)
end
add_form_parameter (k: READABLE_STRING_32; v: READABLE_STRING_32)
-- Add a form parameter `k'= `v'.
do
form_parameters.force (v, k)
end
set_credentials_required (b: BOOLEAN)
-- If b is True, credentials are required, otherwise just optional.
do
credentials_required := b
end
set_upload_data (a_data: like upload_data)
-- Set `upload_data' to `a_data'
--| note: the Current context can have upload_data XOR upload_filename, but not both.
require
has_no_upload_data: a_data /= Void implies not has_upload_data
has_upload_filename: (a_data /= Void and then not a_data.is_empty) implies not has_upload_filename
do
if a_data = Void or else a_data.is_empty then
upload_data := Void
else
upload_data := a_data
end
ensure
(a_data /= Void and then not a_data.is_empty) implies (has_upload_data and not has_upload_filename)
end
set_upload_filename (a_fn: detachable READABLE_STRING_GENERAL)
-- Set `upload_filename' to `a_fn'
--| note: the Current context can have upload_data XOR upload_filename, but not both.
require
has_no_upload_filename: a_fn /= Void implies not has_upload_filename
has_no_upload_data: (a_fn /= Void and then not a_fn.is_empty) implies not has_upload_data
do
if a_fn = Void then
if a_fn = Void or else a_fn.is_empty then
upload_filename := Void
else
create upload_filename.make_from_string_general (a_fn)
end
ensure
(a_fn /= Void and then not a_fn.is_empty) implies (has_upload_filename and not has_upload_data)
end
set_write_agent (agt: like write_agent)
-- Set `write_agent' to `agt'.
do
write_agent := agt
end
set_output_file (f: FILE)
-- Set `output_file' to `f'.
require
f_is_open_write: f.is_open_write
do
@@ -178,6 +202,7 @@ feature -- Element change
end
set_output_content_file (f: FILE)
-- Set `output_content_file' to `f'.
require
f_is_open_write: f.is_open_write
do
@@ -187,6 +212,8 @@ feature -- Element change
feature -- Status setting
set_proxy (a_host: detachable READABLE_STRING_8; a_port: INTEGER)
-- Set proxy to `a_host:a_port'.
--| this can be used for instance with "http://fiddler2.com/" web debugging proxy.
do
if a_host = Void then
proxy := Void
@@ -212,6 +239,7 @@ feature -- Conversion helpers
feature {NONE} -- Implementation
parameters_to_url_encoded_string (ht: HASH_TABLE [READABLE_STRING_32, READABLE_STRING_32]): STRING_8
-- Build url encoded string using parameters from `ht'.
do
create Result.make (64)
from
@@ -230,6 +258,7 @@ feature {NONE} -- Implementation
end
url_encoder: URL_ENCODER
-- Shared URL encoder.
once
create Result
end

View File

@@ -36,9 +36,10 @@ feature {NONE} -- Initialization
end
set_defaults
-- Set default settings.
do
timeout := 5
connect_timeout := 1
timeout := 0 --| never timeout
connect_timeout := 0 --| never timeout
max_redirects := 5
set_basic_auth_type
end
@@ -76,11 +77,15 @@ feature -- Basic operation
end
end
feature -- Custom
custom (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
-- Response for `a_method' request based on Current, `a_path' and `ctx'.
deferred
end
feature -- Helper
get (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
-- Response for GET request based on Current, `a_path' and `ctx'.
deferred
@@ -103,6 +108,18 @@ feature -- Basic operation
deferred
end
patch (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
-- Response for PATCH request based on Current, `a_path' and `ctx'
-- with input `data'
deferred
end
patch_file (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
-- Response for PATCH request based on Current, `a_path' and `ctx'
-- with uploaded data file `fn'
deferred
end
put (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
-- Response for PUT request based on Current, `a_path' and `ctx'
-- with input `data'
@@ -133,10 +150,12 @@ feature -- Status report
feature -- Settings
timeout: INTEGER
-- HTTP transaction timeout in seconds. Defaults to 5 seconds.
-- HTTP transaction timeout in seconds.
-- Defaults to 0 second i.e never timeout.
connect_timeout: INTEGER
-- HTTP connection timeout in seconds. Defaults to 1 second.
-- HTTP connection timeout in seconds.
-- Defaults to 0 second i.e never timeout.
max_redirects: INTEGER
-- Maximum number of times to follow redirects.
@@ -281,7 +300,7 @@ feature -- Element change
end
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
copyright: "2011-2013, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -162,6 +162,7 @@ feature -- Execution
check
post_or_put_request_method: request_method.is_case_insensitive_equal ("POST")
or request_method.is_case_insensitive_equal ("PUT")
or request_method.is_case_insensitive_equal ("PATCH")
end
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_postfields, l_upload_data)
@@ -170,6 +171,7 @@ feature -- Execution
check
post_or_put_request_method: request_method.is_case_insensitive_equal ("POST")
or request_method.is_case_insensitive_equal ("PUT")
or request_method.is_case_insensitive_equal ("PATCH")
end
create l_upload_file.make_with_name (l_upload_filename)

View File

@@ -31,7 +31,7 @@ feature -- Status report
Result := curl.is_dynamic_library_exists
end
feature -- Basic operation
feature -- Custom
custom (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
local
@@ -41,6 +41,18 @@ feature -- Basic operation
Result := req.execute
end
custom_with_upload_data (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: READABLE_STRING_8): HTTP_CLIENT_RESPONSE
do
Result := impl_custom (a_method, a_path, a_ctx, data, Void)
end
custom_with_upload_file (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; fn: READABLE_STRING_8): HTTP_CLIENT_RESPONSE
do
Result := impl_custom (a_method, a_path, a_ctx, Void, fn)
end
feature -- Helper
get (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
do
Result := custom ("GET", a_path, ctx)
@@ -53,63 +65,32 @@ feature -- Basic operation
post (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
do
Result := impl_post (a_path, a_ctx, data, Void)
Result := impl_custom ("POST", a_path, a_ctx, data, Void)
end
post_file (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
do
Result := impl_post (a_path, a_ctx, Void, fn)
Result := impl_custom ("POST", a_path, a_ctx, Void, fn)
end
patch (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
do
Result := impl_custom ("PATCH", a_path, a_ctx, data, Void)
end
patch_file (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
do
Result := impl_custom ("PATCH", a_path, a_ctx, Void, fn)
end
put (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
local
ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT
f: detachable RAW_FILE
l_data: detachable READABLE_STRING_8
do
--| Quick and dirty hack using real file, for PUT uploaded data
--| FIXME [2012-05-23]: better use libcurl for that purpose
ctx := a_ctx
if data /= Void then
if ctx = Void then
create ctx.make
end
ctx.set_upload_data (data)
end
if ctx /= Void then
l_data := ctx.upload_data
end
if l_data /= Void then
create f.make_open_write (create {FILE_NAME}.make_temporary_name)
f.put_string (l_data)
f.close
check ctx /= Void then
ctx.set_upload_data (Void)
ctx.set_upload_filename (f.path.name)
end
end
Result := custom ("PUT", a_path, ctx)
if f /= Void then
f.delete
end
if l_data /= Void and a_ctx /= Void then
a_ctx.set_upload_filename (Void)
a_ctx.set_upload_data (l_data)
end
Result := impl_custom ("PUT", a_path, a_ctx, data, Void)
end
put_file (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
local
ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT
do
ctx := a_ctx
if fn /= Void then
if ctx = Void then
create ctx.make
end
ctx.set_upload_filename (fn)
end
Result := custom ("PUT", a_path, ctx)
Result := impl_custom ("PUT", a_path, a_ctx, Void, fn)
end
delete (a_path: READABLE_STRING_8; ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT): HTTP_CLIENT_RESPONSE
@@ -119,10 +100,12 @@ feature -- Basic operation
feature {NONE} -- Implementation
impl_post (a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
impl_custom (a_method: READABLE_STRING_8; a_path: READABLE_STRING_8; a_ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT; data: detachable READABLE_STRING_8; fn: detachable READABLE_STRING_8): HTTP_CLIENT_RESPONSE
local
req: HTTP_CLIENT_REQUEST
ctx: detachable HTTP_CLIENT_REQUEST_CONTEXT
f: detachable RAW_FILE
l_data: detachable READABLE_STRING_8
do
ctx := a_ctx
if data /= Void then
@@ -137,8 +120,35 @@ feature {NONE} -- Implementation
end
ctx.set_upload_filename (fn)
end
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, "POST", Current, ctx)
if ctx /= Void then
l_data := ctx.upload_data
if l_data /= Void and a_method.is_case_insensitive_equal_general ("PUT") then
--| Quick and dirty hack using real file, for PUT uploaded data
--| FIXME [2012-05-23]: better use libcurl for that purpose
if ctx.has_upload_filename then
check put_conflict_file_and_data: False end
end
create f.make_open_write (create {FILE_NAME}.make_temporary_name)
f.put_string (l_data)
f.close
check ctx /= Void then
ctx.set_upload_data (Void)
ctx.set_upload_filename (f.path.name)
end
end
end
create {LIBCURL_HTTP_CLIENT_REQUEST} req.make (base_url + a_path, a_method, Current, ctx)
Result := req.execute
if f /= Void then
f.delete
end
if l_data /= Void and a_ctx /= Void then
a_ctx.set_upload_filename (Void)
a_ctx.set_upload_data (l_data)
end
end
feature {LIBCURL_HTTP_CLIENT_REQUEST} -- Curl implementation

View File

@@ -8,10 +8,14 @@
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
<assertions precondition="true"/>
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http_client" location="..\http_client-safe.ecf" readonly="false"/>
<library name="http_client" location="..\http_client-safe.ecf" readonly="false" use_application_options="true">
<option>
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
</library>
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
<tests name="tests" location=".\"/>
</target>

View File

@@ -1,125 +0,0 @@
CONNEG is a library that provides utilities to select the best repesentation of a resource for a client
where there are multiple representations available.
Using this labrary you can retrieve the best Variant for media type, language preference, enconding and compression.
The library is based on eMIME Eiffel MIME library based on Joe Gregorio code
Take into account that the library is under development so is expected that the API change.
The library contains utilities that deal with content negotiation (server driven negotiation).This utility class
is based on ideas taken from the Book Restful WebServices Cookbook
The class CONNEG_SERVER_SIDE contains several features that helps to write different type of negotiations (media type, language,
charset and compression).
So for each of the following questions, you will have a corresponding method to help in the solution.
- How to implement Media type negotiation?
Hint: Use CONNEG_SERVER_SIDE.media_type_preference
- How to implement Language Negotiation?
Hint: Use CONNEG_SERVER_SIDE.language_preference
- How to implement Character encoding Negotiation?
Hint: Use CONNEG_SERVER_SIDE.charset_preference
- How to implement Compression Negotiation?
Hint: Use CONNEG_SERVER_SIDE.encoding_preference
There is also a [test case](test/conneg_server_side_test.e "conneg_server_side_test") where you can check how to use this class.
note
description: "Summary description for CONNEG_SERVER_SIDE. Utility class to support Server Side Content Negotiation "
author: ""
date: "$Date$"
revision: "$Revision$"
description: "[
Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1
Server-driven Negotiation : If the selection of the best representation for a response is made by an algorithm located at the server,
it is called server-driven negotiation. Selection is based on the available representations of the response (the dimensions over which it can vary; e.g. language, content-coding, etc.)
and the contents of particular header fields in the request message or on other information pertaining to the request (such as the network address of the client).
Server-driven negotiation is advantageous when the algorithm for selecting from among the available representations is difficult to describe to the user agent,
or when the server desires to send its "best guess" to the client along with the first response (hoping to avoid the round-trip delay of a subsequent request if the "best guess" is good enough for the user).
In order to improve the server's guess, the user agent MAY include request header fields (Accept, Accept-Language, Accept-Encoding, etc.) which describe its preferences for such a response.
]"
class interface
CONNEG_SERVER_SIDE
create
make
feature -- Initialization
make (a_mime: STRING_8; a_language: STRING_8; a_charset: STRING_8; an_encoding: STRING_8)
feature -- Compression Negotiation
encoding_preference (server_encoding_supported: LIST [STRING_8]; header: STRING_8): COMPRESSION_VARIANT_RESULTS
-- server_encoding_supported represent a list of encoding supported by the server.
-- header represent the Accept-Encoding header, ie, the client preferences.
-- Return which Encoding to use in a response, if the server support
-- one Encoding, or empty in other case.
-- Representation: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
feature -- Encoding Negotiation
charset_preference (server_charset_supported: LIST [STRING_8]; header: STRING_8): CHARACTER_ENCODING_VARIANT_RESULTS
-- server_charset_supported represent a list of charset supported by the server.
-- header represent the Accept-Charset header, ie, the client preferences.
-- Return which Charset to use in a response, if the server support
-- one Charset, or empty in other case.
-- Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2
feature -- Language Negotiation
language_preference (server_language_supported: LIST [STRING_8]; header: STRING_8): LANGUAGE_VARIANT_RESULTS
-- server_language_supported represent a list of languages supported by the server.
-- header represent the Accept-Language header, ie, the client preferences.
-- Return which Language to use in a response, if the server support
-- one Language, or empty in other case.
-- Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
feature -- Media Type Negotiation
media_type_preference (mime_types_supported: LIST [STRING_8]; header: STRING_8): MEDIA_TYPE_VARIANT_RESULTS
-- mime_types_supported represent media types supported by the server.
-- header represent the Accept header, ie, the client preferences.
-- Return which media type to use for representaion in a response, if the server support
-- one media type, or empty in other case.
-- Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
feature -- Server Side Defaults Formats
charset_default: STRING_8
encoding_default: STRING_8
language_default: STRING_8
mime_default: STRING_8
set_charset_default (a_charset: STRING_8)
-- set the charset_default with `a_charset'
ensure
set_charset: a_charset ~ charset_default
set_encoding_defautl (an_encoding: STRING_8)
ensure
set_encoding: an_encoding ~ encoding_default
set_language_default (a_language: STRING_8)
-- set the language_default with `a_language'
ensure
set_language: a_language ~ language_default
set_mime_default (a_mime: STRING_8)
-- set the mime_default with `a_mime'
ensure
set_mime_default: a_mime ~ mime_default
note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end -- class CONNEG_SERVER_SIDE

View File

@@ -1,79 +0,0 @@
#!/usr/bin/env ruby
# Niklaus Giger, 15.01.2011
# Small ruby-script run all tests using ec (the Eiffel compiler)
# we assumen that ec outputs everything in english!
# For the command line options look at
# http://docs.eiffel.com/book/eiffelstudio/eiffelstudio-command-line-options
# we use often the -batch open.
#
# TODO: Fix problems when compiling takes too long and/or there
# are ec process lingering around from a previous failed build
require 'tempfile'
require 'fileutils'
# Override system command.
# run command. if not successful, complain and exit with error
def system(cmd)
puts cmd
res = Kernel.system(cmd)
if !res
puts "Failed running: #{cmd}"
exit 2
end
end
def runTestForProject(where)
if !File.directory?(where)
puts "Directory #{where} does not exist"
exit 2
end
# create a temporary file with input for the
# interactive mode of ec
commands2run=<<EOF
T
E
q
EOF
file = Tempfile.new('commands2run')
file.puts commands2run
file.close
Dir.chdir(where)
# First we have to remove old compilation
FileUtils.rm_rf("EIFGENs")
# compile the library
cmd = "ec -config library/emime-safe.ecf -target emime -batch -c_compile"
res = system(cmd)
# compile the test
cmd = "ec -config test/test-safe.ecf -target test -batch -c_compile"
res = system(cmd)
logFile = "#{__FILE__}.log"
sleep 1
cmd = "ec -config test/test-safe.ecf -target test -batch -loop 1>#{logFile} 2>#{__FILE__}.auto_test_output <#{file.path}"
res = system(cmd)
m= nil
IO.readlines(logFile).each{
|line|
m = /(\d+) tests total \((\d+) executed, (\d+) failing, (\d+) unresolved/.match(line)
break if m
}
puts
if m[3].to_i == 0 and m[4].to_i == 0 then
puts "#{m[1]} tests completed successfully"
else
puts "Failures while running #{m[1]} failed. #{m[2]} executed #{m[3]} failures #{m[4]} unresolved"
exit 2
end
end
runTestForProject(Dir.pwd)

View File

@@ -1,45 +0,0 @@
note
description: "Summary description for {CHARACTER_ENCODING_VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
CHARACTER_ENCODING_VARIANT_RESULTS
feature
character_type : detachable STRING
set_character_type ( a_character_type: STRING)
do
character_type := a_character_type
ensure
set_character_type : a_character_type ~ character_type
end
variant_header : detachable STRING
set_variant_header
do
variant_header := "Accept-Charset"
end
supported_variants : detachable LIST[STRING]
set_supported_variants (a_supported : LIST[STRING])
do
supported_variants := a_supported
ensure
set_supported_variants : supported_variants = a_supported
end
is_acceptable : BOOLEAN
set_acceptable ( acceptable : BOOLEAN)
do
is_acceptable := acceptable
ensure
is_acceptable = acceptable
end
note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,282 +0,0 @@
note
description: "COMMON_ACCEPT_HEADER_PARSER, this class allows to parse Accept-Charset and Accept-Encoding headers"
author: ""
date: "$Date$"
revision: "$Revision$"
description : "[
Charset Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2
Encoding Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
]"
class
COMMON_ACCEPT_HEADER_PARSER
feature -- Parser
parse_common (header: STRING): COMMON_RESULTS
-- Parses `header' charset/encoding into its component parts.
-- For example, the charset 'iso-8889-5' would get parsed
-- into:
-- ('iso-8889-5', {'q':'1.0'})
local
l_parts: LIST [STRING]
sub_parts: LIST [STRING]
p: STRING
i: INTEGER
l_header: STRING
do
create Result.make
l_parts := header.split (';')
if l_parts.count = 1 then
Result.put ("1.0", "q")
else
from
i := 1
until
i > l_parts.count
loop
p := l_parts.at (i)
sub_parts := p.split ('=')
if sub_parts.count = 2 then
Result.put (trim (sub_parts[2]), trim (sub_parts[1]))
end
i := i + 1
end
end
l_header := trim (l_parts[1])
Result.set_field (trim (l_header))
end
fitness_and_quality_parsed (a_field: STRING; parsed_charsets: LIST [COMMON_RESULTS]): FITNESS_AND_QUALITY
-- Find the best match for a given charset/encoding against a list of charsets/encodings
-- that have already been parsed by parse_common. Returns a
-- tuple of the fitness value and the value of the 'q' quality parameter of
-- the best match, or (-1, 0) if no match was found. Just as for
-- quality_parsed().
local
best_fitness: INTEGER
target_q: REAL_64
best_fit_q: REAL_64
target: COMMON_RESULTS
range: COMMON_RESULTS
element: detachable STRING
l_fitness: INTEGER
do
best_fitness := -1
best_fit_q := 0.0
target := parse_common(a_field)
if attached target.item ("q") as q and then q.is_double then
target_q := q.to_double
if target_q < 0.0 then
target_q := 0.0
elseif target_q > 1.0 then
target_q := 1.0
end
else
target_q := 1.0
end
if attached target.field as l_target_field
then
from
parsed_charsets.start
until
parsed_charsets.after
loop
range := parsed_charsets.item_for_iteration
if attached range.field as l_range_common then
if l_target_field.same_string (l_range_common) or l_target_field.same_string ("*") or l_range_common.same_string ("*") then
if l_range_common.same_string (l_target_field) then
l_fitness := 100
else
l_fitness := 0
end
if l_fitness > best_fitness then
best_fitness := l_fitness
element := range.item ("q")
if element /= Void then
best_fit_q := element.to_double.min (target_q)
else
best_fit_q := 0.0
end
end
end
end
parsed_charsets.forth
end
end
create Result.make (best_fitness, best_fit_q)
end
quality_parsed (a_field: STRING; parsed_common: LIST [COMMON_RESULTS]): REAL_64
-- Find the best match for a given charset/encoding against a list of charsets/encodings that
-- have already been parsed by parse_charsets(). Returns the 'q' quality
-- parameter of the best match, 0 if no match was found. This function
-- bahaves the same as quality()
do
Result := fitness_and_quality_parsed (a_field, parsed_common).quality
end
quality (a_field: STRING; commons: STRING): REAL_64
-- Returns the quality 'q' of a charset/encoding when compared against the
-- a list of charsets/encodings/
local
l_commons : LIST [STRING]
res : ARRAYED_LIST [COMMON_RESULTS]
p_res : COMMON_RESULTS
do
l_commons := commons.split (',')
from
create res.make (10);
l_commons.start
until
l_commons.after
loop
p_res := parse_common (l_commons.item_for_iteration)
res.put_left (p_res)
l_commons.forth
end
Result := quality_parsed (a_field, res)
end
best_match (supported: LIST [STRING]; header: STRING): STRING
-- Choose the accept with the highest fitness score and quality ('q') from a list of candidates.
local
l_header_results: LIST [COMMON_RESULTS]
weighted_matches: LIST [FITNESS_AND_QUALITY]
l_res: LIST [STRING]
p_res: COMMON_RESULTS
fitness_and_quality, first_one: detachable FITNESS_AND_QUALITY
do
l_res := header.split (',')
create {ARRAYED_LIST [COMMON_RESULTS]} l_header_results.make (l_res.count)
from
l_res.start
until
l_res.after
loop
p_res := parse_common (l_res.item_for_iteration)
l_header_results.force (p_res)
l_res.forth
end
create {ARRAYED_LIST [FITNESS_AND_QUALITY]} weighted_matches.make (supported.count)
from
supported.start
until
supported.after
loop
fitness_and_quality := fitness_and_quality_parsed (supported.item_for_iteration, l_header_results)
fitness_and_quality.set_mime_type (mime_type (supported.item_for_iteration))
weighted_matches.force (fitness_and_quality)
supported.forth
end
--| Keep only top quality+fitness types
--| TODO extract method
from
weighted_matches.start
first_one := weighted_matches.item
weighted_matches.forth
until
weighted_matches.after
loop
fitness_and_quality := weighted_matches.item
if first_one < fitness_and_quality then
first_one := fitness_and_quality
if not weighted_matches.isfirst then
from
weighted_matches.back
until
weighted_matches.before
loop
weighted_matches.remove
weighted_matches.back
end
weighted_matches.forth
end
check weighted_matches.item = fitness_and_quality end
weighted_matches.forth
elseif first_one.is_equal (fitness_and_quality) then
weighted_matches.forth
else
check first_one > fitness_and_quality end
weighted_matches.remove
end
end
if first_one /= Void and then first_one.quality /= 0.0 then
if weighted_matches.count = 1 then
Result := first_one.mime_type
else
from
fitness_and_quality := Void
l_header_results.start
until
l_header_results.after or fitness_and_quality /= Void
loop
if attached l_header_results.item.field as l_field then
from
weighted_matches.start
until
weighted_matches.after or fitness_and_quality /= Void
loop
fitness_and_quality := weighted_matches.item
if fitness_and_quality.mime_type.same_string (l_field) then
--| Found
else
fitness_and_quality := Void
weighted_matches.forth
end
end
else
check has_field: False end
end
l_header_results.forth
end
if fitness_and_quality /= Void then
Result := fitness_and_quality.mime_type
else
Result := first_one.mime_type
end
end
else
Result := ""
end
end
feature -- Util
mime_type (s: STRING): STRING
local
p: INTEGER
do
p := s.index_of (';', 1)
if p > 0 then
Result := trim (s.substring (1, p - 1))
else
Result := trim (s.string)
end
end
trim (a_string: STRING): STRING
-- trim whitespace from the beginning and end of a string
require
valid_argument : a_string /= Void
do
a_string.left_adjust
a_string.right_justify
Result := a_string
ensure
result_same_as_argument: a_string = Result
end
note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,119 +0,0 @@
note
description: "Summary description for {COMMON_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
COMMON_RESULTS
inherit
ANY
redefine
out
end
DEBUG_OUTPUT
redefine
out
end
create
make
feature -- Initialization
make
do
create params.make (2)
end
feature -- Access
field: detachable STRING
item (a_key: STRING): detachable STRING
-- Item associated with `a_key', if present
-- otherwise default value of type `STRING'
do
Result := params.item (a_key)
end
keys: LIST [STRING]
-- arrays of currents keys
local
res: ARRAYED_LIST [STRING]
do
create res.make_from_array (params.current_keys)
Result := res
end
has_key (a_key: STRING): BOOLEAN
-- Is there an item in the table with key `a_key'?
do
Result := params.has_key (a_key)
end
feature -- Element change
set_field (a_field: STRING)
-- Set type with `a_charset'
do
field := a_field
ensure
field_assigned: field ~ field
end
put (new: STRING; key: STRING)
-- Insert `new' with `key' if there is no other item
-- associated with the same key. If present, replace
-- the old value with `new'
do
if params.has_key (key) then
params.replace (new, key)
else
params.force (new, key)
end
ensure
has_key: params.has_key (key)
has_item: params.has_item (new)
end
feature -- Status Report
out: STRING
-- Representation of the current object
do
create Result.make_from_string ("(")
if attached field as t then
Result.append_string ("'" + t + "',")
end
Result.append_string (" {")
from
params.start
until
params.after
loop
Result.append ("'" + params.key_for_iteration + "':'" + params.item_for_iteration + "',");
params.forth
end
Result.append ("})")
end
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := out
end
feature {NONE} -- Implementation
params: HASH_TABLE [STRING, STRING]
--dictionary of all the parameters for the media range
;note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,44 +0,0 @@
note
description: "Summary description for {COMPRESSION_VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
COMPRESSION_VARIANT_RESULTS
feature
compression_type : detachable STRING
set_compression_type ( a_compression_type: STRING)
do
compression_type := a_compression_type
ensure
set_compression_type : a_compression_type ~ compression_type
end
variant_header : detachable STRING
set_variant_header
do
variant_header := "Accept-Encoding"
end
supported_variants : detachable LIST[STRING]
set_supported_variants (a_supported : LIST[STRING])
do
supported_variants := a_supported
ensure
set_supported_variants : supported_variants = a_supported
end
is_acceptable : BOOLEAN
set_acceptable ( acceptable : BOOLEAN)
do
is_acceptable := acceptable
ensure
is_acceptable = acceptable
end
note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,216 +0,0 @@
note
description: "Summary description for {CONNEG_SERVER_SIDE}. Utility class to support Server Side Content Negotiation "
author: ""
date: "$Date$"
revision: "$Revision$"
description: "[
Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12.1
Server-driven Negotiation : If the selection of the best representation for a response is made by an algorithm located at the server,
it is called server-driven negotiation. Selection is based on the available representations of the response (the dimensions over which it can vary; e.g. language, content-coding, etc.)
and the contents of particular header fields in the request message or on other information pertaining to the request (such as the network address of the client).
Server-driven negotiation is advantageous when the algorithm for selecting from among the available representations is difficult to describe to the user agent,
or when the server desires to send its "best guess" to the client along with the first response (hoping to avoid the round-trip delay of a subsequent request if the "best guess" is good enough for the user).
In order to improve the server's guess, the user agent MAY include request header fields (Accept, Accept-Language, Accept-Encoding, etc.) which describe its preferences for such a response.
]"
class
CONNEG_SERVER_SIDE
inherit
SHARED_CONNEG
REFACTORING_HELPER
create
make
feature -- Initialization
make ( a_mime: STRING; a_language : STRING; a_charset :STRING; an_encoding: STRING)
do
set_mime_default (a_mime)
set_language_default (a_language)
set_charset_default (a_charset)
set_encoding_defautl (an_encoding)
end
feature -- Server Side Defaults Formats
mime_default : STRING
set_mime_default ( a_mime: STRING)
-- set the mime_default with `a_mime'
do
mime_default := a_mime
ensure
set_mime_default: a_mime ~ mime_default
end
language_default : STRING
set_language_default (a_language : STRING)
-- set the language_default with `a_language'
do
language_default := a_language
ensure
set_language : a_language ~ language_default
end
charset_default : STRING
set_charset_default (a_charset : STRING)
-- set the charset_default with `a_charset'
do
charset_default := a_charset
ensure
set_charset : a_charset ~ charset_default
end
encoding_default : STRING
set_encoding_defautl (an_encoding : STRING)
do
encoding_default := an_encoding
ensure
set_encoding : an_encoding ~ encoding_default
end
feature -- Media Type Negotiation
media_type_preference ( mime_types_supported : LIST[STRING]; header: detachable READABLE_STRING_8) : MEDIA_TYPE_VARIANT_RESULTS
-- mime_types_supported represent media types supported by the server.
-- header represent the Accept header, ie, the client preferences.
-- Return which media type to use for representaion in a response, if the server support
-- one media type, or empty in other case.
-- Reference : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
local
mime_match: STRING
do
create Result
if header = Void or else header.is_empty then
-- the request has no Accept header, ie the header is empty, in this case we use the default format
Result.set_acceptable (TRUE)
Result.set_media_type (mime_default)
else
-- select the best match, server support, client preferences
mime_match := mime.best_match (mime_types_supported, header)
if mime_match.is_empty then
-- The server does not support any of the media types prefered by the client
Result.set_acceptable (False)
Result.set_supported_variants (mime_types_supported)
else
-- Set the best match
Result.set_media_type(mime_match)
Result.set_acceptable (True)
Result.set_variant_header
end
end
end
feature -- Encoding Negotiation
charset_preference (server_charset_supported : LIST[STRING]; header: detachable READABLE_STRING_8) : CHARACTER_ENCODING_VARIANT_RESULTS
-- server_charset_supported represent a list of charset supported by the server.
-- header represent the Accept-Charset header, ie, the client preferences.
-- Return which Charset to use in a response, if the server support
-- one Charset, or empty in other case.
-- Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.2
local
charset_match : STRING
do
create Result
if header = Void or else header.is_empty then
-- the request has no Accept-Charset header, ie the header is empty, in this case use default charset encoding
-- (UTF-8)
Result.set_acceptable (TRUE)
Result.set_character_type (charset_default)
else
-- select the best match, server support, client preferences
charset_match := common.best_match (server_charset_supported, header)
if charset_match.is_empty then
-- The server does not support any of the compression types prefered by the client
Result.set_acceptable (False)
Result.set_supported_variants (server_charset_supported)
else
-- Set the best match
Result.set_character_type(charset_match)
Result.set_acceptable (True)
Result.set_variant_header
end
end
end
feature -- Compression Negotiation
encoding_preference (server_encoding_supported : LIST[STRING]; header: detachable READABLE_STRING_8) : COMPRESSION_VARIANT_RESULTS
-- server_encoding_supported represent a list of encoding supported by the server.
-- header represent the Accept-Encoding header, ie, the client preferences.
-- Return which Encoding to use in a response, if the server support
-- one Encoding, or empty in other case.
-- Representation: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
local
compression_match : STRING
do
create Result
if header = Void or else header.is_empty then
-- the request has no Accept-Encoding header, ie the header is empty, in this case do not compress representations
Result.set_acceptable (TRUE)
Result.set_compression_type (encoding_default)
else
-- select the best match, server support, client preferences
compression_match := common.best_match (server_encoding_supported, header)
if compression_match.is_empty then
-- The server does not support any of the compression types prefered by the client
Result.set_acceptable (False)
Result.set_supported_variants (server_encoding_supported)
else
-- Set the best match
Result.set_compression_type(compression_match)
Result.set_acceptable (True)
Result.set_variant_header
end
end
end
feature -- Language Negotiation
language_preference (server_language_supported : LIST[STRING]; header: detachable READABLE_STRING_8) : LANGUAGE_VARIANT_RESULTS
-- server_language_supported represent a list of languages supported by the server.
-- header represent the Accept-Language header, ie, the client preferences.
-- Return which Language to use in a response, if the server support
-- one Language, or empty in other case.
-- Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
local
language_match: STRING
do
create Result
if header = Void or else header.is_empty then
-- the request has no Accept header, ie the header is empty, in this case we use the default format
Result.set_acceptable (TRUE)
Result.set_language_type (language_default)
else
-- select the best match, server support, client preferences
language_match := language.best_match (server_language_supported, header)
if language_match.is_empty then
-- The server does not support any of the media types prefered by the client
Result.set_acceptable (False)
Result.set_supported_variants (server_language_supported)
else
-- Set the best match
Result.set_language_type(language_match)
Result.set_acceptable (True)
Result.set_variant_header
end
end
end
feature -- Apache Conneg Algorithm
note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,352 +0,0 @@
note
description: "Summary description for {LANGUAGE_PARSE}."
author: ""
date: "$Date$"
revision: "$Revision$"
description : "Language Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4"
class
LANGUAGE_PARSE
inherit
REFACTORING_HELPER
feature -- Parser
parse_mime_type (a_mime_type: STRING): LANGUAGE_RESULTS
-- Parses a mime-type into its component parts.
-- For example, the media range 'application/xhtml;q=0.5' would get parsed
-- into:
-- ('application', 'xhtml', {'q', '0.5'})
local
l_parts: LIST [STRING]
p: STRING
sub_parts: LIST [STRING]
i: INTEGER
l_full_type: STRING
l_types: LIST [STRING]
do
fixme ("Improve code!!!")
create Result.make
l_parts := a_mime_type.split (';')
from
i := 1
until
i > l_parts.count
loop
p := l_parts.at (i)
sub_parts := p.split ('=')
if sub_parts.count = 2 then
Result.put (trim (sub_parts[2]), trim (sub_parts[1]))
end
i := i + 1
end
--Java URLConnection class sends an Accept header that includes a
--single "*" - Turn it into a legal wildcard.
l_full_type := trim (l_parts[1])
if l_full_type.same_string ("*") then
l_full_type := "*"
end
l_types := l_full_type.split ('-')
if l_types.count = 1 then
Result.set_type (trim (l_types[1]))
else
Result.set_type (trim (l_types[1]))
Result.set_sub_type (trim (l_types[2]))
end
end
parse_media_range (a_range: STRING): LANGUAGE_RESULTS
-- Media-ranges are mime-types with wild-cards and a 'q' quality parameter.
-- For example, the media range 'application/*;q=0.5' would get parsed into:
-- ('application', '*', {'q', '0.5'})
-- In addition this function also guarantees that there is a value for 'q'
-- in the params dictionary, filling it in with a proper default if
-- necessary.
do
fixme ("Improve the code!!!")
Result := parse_mime_type (a_range)
if attached Result.item ("q") as q then
if
q.is_double and then
attached {REAL_64} q.to_double as r and then
(r >= 0.0 and r <= 1.0)
then
--| Keep current value
if q.same_string ("1") then
--| Use 1.0 formatting
Result.put ("1.0", "q")
end
else
Result.put ("1.0", "q")
end
else
Result.put ("1.0", "q")
end
end
fitness_and_quality_parsed (a_mime_type: STRING; parsed_ranges: LIST [LANGUAGE_RESULTS]): FITNESS_AND_QUALITY
-- Find the best match for a given mimeType against a list of media_ranges
-- that have already been parsed by parse_media_range. Returns a
-- tuple of the fitness value and the value of the 'q' quality parameter of
-- the best match, or (-1, 0) if no match was found. Just as for
-- quality_parsed(), 'parsed_ranges' must be a list of parsed media ranges.
local
best_fitness: INTEGER
target_q: REAL_64
best_fit_q: REAL_64
target: LANGUAGE_RESULTS
range: LANGUAGE_RESULTS
keys: LIST [STRING]
param_matches: INTEGER
element: detachable STRING
l_fitness: INTEGER
do
best_fitness := -1
best_fit_q := 0.0
target := parse_media_range (a_mime_type)
if attached target.item ("q") as q and then q.is_double then
target_q := q.to_double
if target_q < 0.0 then
target_q := 0.0
elseif target_q > 1.0 then
target_q := 1.0
end
else
target_q := 1.0
end
if
attached target.type as l_target_type
then
from
parsed_ranges.start
until
parsed_ranges.after
loop
range := parsed_ranges.item_for_iteration
if
(
attached range.type as l_range_type and then
(l_target_type.same_string (l_range_type) or l_range_type.same_string ("*") or l_target_type.same_string ("*"))
)
then
from
param_matches := 0
keys := target.keys
keys.start
until
keys.after
loop
element := keys.item_for_iteration
if
not element.same_string ("q") and then
range.has_key (element) and then
(attached target.item (element) as t_item and attached range.item (element) as r_item) and then
t_item.same_string (r_item)
then
param_matches := param_matches + 1
end
keys.forth
end
if l_range_type.same_string (l_target_type) then
l_fitness := 100
else
l_fitness := 0
end
if (
attached range.sub_type as l_range_sub_type and then attached target.sub_type as l_target_sub_type and then
(l_target_sub_type.same_string (l_range_sub_type) or l_range_sub_type.same_string ("*") or l_target_sub_type.same_string ("*"))
) then
if l_range_sub_type.same_string (l_target_sub_type) then
l_fitness := l_fitness + 10
end
end
l_fitness := l_fitness + param_matches
if l_fitness > best_fitness then
best_fitness := l_fitness
element := range.item ("q")
if element /= Void then
best_fit_q := element.to_double.min (target_q)
else
best_fit_q := 0.0
end
end
end
parsed_ranges.forth
end
end
create Result.make (best_fitness, best_fit_q)
end
quality_parsed (a_mime_type: STRING; parsed_ranges: LIST [LANGUAGE_RESULTS]): REAL_64
-- Find the best match for a given mime-type against a list of ranges that
-- have already been parsed by parseMediaRange(). Returns the 'q' quality
-- parameter of the best match, 0 if no match was found. This function
-- bahaves the same as quality() except that 'parsed_ranges' must be a list
-- of parsed media ranges.
do
Result := fitness_and_quality_parsed (a_mime_type, parsed_ranges).quality
end
quality (a_mime_type: STRING; ranges: STRING): REAL_64
-- Returns the quality 'q' of a mime-type when compared against the
-- mediaRanges in ranges.
local
l_ranges : LIST [STRING]
res : ARRAYED_LIST [LANGUAGE_RESULTS]
p_res : LANGUAGE_RESULTS
do
l_ranges := ranges.split (',')
from
create res.make (10);
l_ranges.start
until
l_ranges.after
loop
p_res := parse_media_range (l_ranges.item_for_iteration)
res.put_left (p_res)
l_ranges.forth
end
Result := quality_parsed (a_mime_type, res)
end
best_match (supported: LIST [STRING]; header: STRING): STRING
-- Choose the mime-type with the highest fitness score and quality ('q') from a list of candidates.
local
l_header_results: LIST [LANGUAGE_RESULTS]
weighted_matches: LIST [FITNESS_AND_QUALITY]
l_res: LIST [STRING]
p_res: LANGUAGE_RESULTS
fitness_and_quality, first_one: detachable FITNESS_AND_QUALITY
s: STRING
do
l_res := header.split (',')
create {ARRAYED_LIST [LANGUAGE_RESULTS]} l_header_results.make (l_res.count)
fixme("Extract method!!!")
from
l_res.start
until
l_res.after
loop
p_res := parse_media_range (l_res.item_for_iteration)
l_header_results.force (p_res)
l_res.forth
end
create {ARRAYED_LIST [FITNESS_AND_QUALITY]} weighted_matches.make (supported.count)
from
supported.start
until
supported.after
loop
fitness_and_quality := fitness_and_quality_parsed (supported.item_for_iteration, l_header_results)
fitness_and_quality.set_mime_type (mime_type (supported.item_for_iteration))
weighted_matches.force (fitness_and_quality)
supported.forth
end
--| Keep only top quality+fitness types
from
weighted_matches.start
first_one := weighted_matches.item
weighted_matches.forth
until
weighted_matches.after
loop
fitness_and_quality := weighted_matches.item
if first_one < fitness_and_quality then
first_one := fitness_and_quality
if not weighted_matches.isfirst then
from
weighted_matches.back
until
weighted_matches.before
loop
weighted_matches.remove
weighted_matches.back
end
weighted_matches.forth
end
check weighted_matches.item = fitness_and_quality end
weighted_matches.forth
elseif first_one.is_equal (fitness_and_quality) then
weighted_matches.forth
else
check first_one > fitness_and_quality end
weighted_matches.remove
end
end
if first_one /= Void and then first_one.quality /= 0.0 then
if weighted_matches.count = 1 then
Result := first_one.mime_type
else
from
fitness_and_quality := Void
l_header_results.start
until
l_header_results.after or fitness_and_quality /= Void
loop
s := l_header_results.item.mime_type
from
weighted_matches.start
until
weighted_matches.after or fitness_and_quality /= Void
loop
fitness_and_quality := weighted_matches.item
if fitness_and_quality.mime_type.same_string (s) then
--| Found
else
fitness_and_quality := Void
weighted_matches.forth
end
end
l_header_results.forth
end
if fitness_and_quality /= Void then
Result := fitness_and_quality.mime_type
else
Result := first_one.mime_type
end
end
else
Result := ""
end
end
feature {NONE} -- Implementation
mime_type (s: STRING): STRING
local
p: INTEGER
do
p := s.index_of (';', 1)
if p > 0 then
Result := trim (s.substring (1, p - 1))
else
Result := trim (s.string)
end
end
trim (a_string: STRING): STRING
-- trim whitespace from the beginning and end of a string
require
valid_argument : a_string /= Void
do
a_string.left_adjust
a_string.right_justify
Result := a_string
ensure
result_same_as_argument: a_string = Result
end
note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,143 +0,0 @@
note
description: "Summary description for {LANGUAGE_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
LANGUAGE_RESULTS
inherit
ANY
redefine
out
end
DEBUG_OUTPUT
redefine
out
end
create
make
feature -- Initialization
make
do
create params.make (2)
create mime_type.make_from_string ("*")
end
feature -- Access
type: detachable STRING
sub_type: detachable STRING
mime_type: STRING
item (a_key: STRING): detachable STRING
-- Item associated with `a_key', if present
-- otherwise default value of type `STRING'
do
Result := params.item (a_key)
end
keys: LIST [STRING]
-- arrays of currents keys
local
res: ARRAYED_LIST [STRING]
do
create res.make_from_array (params.current_keys)
Result := res
end
has_key (a_key: STRING): BOOLEAN
-- Is there an item in the table with key `a_key'?
do
Result := params.has_key (a_key)
end
feature -- Element change
set_type (a_type: STRING)
-- Set type with `a_type'
do
type := a_type
if attached sub_type as st then
mime_type := a_type + "-" + st
else
mime_type := a_type
end
ensure
type_assigned: type ~ a_type
end
set_sub_type (a_sub_type: STRING)
-- Set sub_type with `a_sub_type
do
sub_type := a_sub_type
if attached type as t then
mime_type := t + "-" + a_sub_type
else
mime_type := "*"
end
ensure
sub_type_assigned: sub_type ~ a_sub_type
end
put (new: STRING; key: STRING)
-- Insert `new' with `key' if there is no other item
-- associated with the same key. If present, replace
-- the old value with `new'
do
if params.has_key (key) then
params.replace (new, key)
else
params.force (new, key)
end
ensure
has_key: params.has_key (key)
has_item: params.has_item (new)
end
feature -- Status Report
out: STRING
-- Representation of the current object
do
create Result.make_from_string ("(")
if attached type as t then
Result.append_string ("'" + t + "',")
end
if attached sub_type as st then
Result.append_string (" '" + st + "',")
end
Result.append_string (" {")
from
params.start
until
params.after
loop
Result.append ("'" + params.key_for_iteration + "':'" + params.item_for_iteration + "',");
params.forth
end
Result.append ("})")
end
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := out
end
feature {NONE} -- Implementation
params: HASH_TABLE [STRING, STRING]
--dictionary of all the parameters for the media range
;note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,46 +0,0 @@
note
description: "Summary description for {LANGUAGE_VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
LANGUAGE_VARIANT_RESULTS
feature
language_type : detachable STRING
set_language_type ( a_language_type: STRING)
do
language_type := a_language_type
ensure
set_language_type : a_language_type ~ language_type
end
variant_header : detachable STRING
set_variant_header
do
variant_header := "Accept-Language"
end
supported_variants : detachable LIST[STRING]
set_supported_variants (a_supported : LIST[STRING])
do
supported_variants := a_supported
ensure
set_supported_variants : supported_variants = a_supported
end
is_acceptable : BOOLEAN
set_acceptable ( acceptable : BOOLEAN)
do
is_acceptable := acceptable
ensure
is_acceptable = acceptable
end
note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,47 +0,0 @@
note
description: "Summary description for {MEDIA_TYPE_VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
MEDIA_TYPE_VARIANT_RESULTS
feature
media_type : detachable STRING
set_media_type ( a_media_type: STRING)
do
media_type := a_media_type
ensure
set_media_type : a_media_type ~ media_type
end
variant_header : detachable STRING
set_variant_header
do
variant_header := "Accept"
end
supported_variants : detachable LIST[STRING]
set_supported_variants (a_supported : LIST[STRING])
do
supported_variants := a_supported
ensure
set_supported_variants : supported_variants = a_supported
end
is_acceptable : BOOLEAN
set_acceptable ( acceptable : BOOLEAN)
do
is_acceptable := acceptable
ensure
is_acceptable = acceptable
end
note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,144 +0,0 @@
note
description: "Summary description for {PARSE_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
PARSE_RESULTS
inherit
ANY
redefine
out
end
DEBUG_OUTPUT
redefine
out
end
create
make
feature -- Initialization
make
do
create params.make (2)
create mime_type.make_from_string ("*/*")
end
feature -- Access
type: detachable STRING
sub_type: detachable STRING
mime_type: STRING
item (a_key: STRING): detachable STRING
-- Item associated with `a_key', if present
-- otherwise default value of type `STRING'
do
Result := params.item (a_key)
end
keys: LIST [STRING]
-- arrays of currents keys
local
res: ARRAYED_LIST [STRING]
do
create res.make_from_array (params.current_keys)
Result := res
end
has_key (a_key: STRING): BOOLEAN
-- Is there an item in the table with key `a_key'?
do
Result := params.has_key (a_key)
end
feature -- Element change
set_type (a_type: STRING)
-- Set type with `a_type'
do
type := a_type
if attached sub_type as st then
mime_type := a_type + "/" + st
else
mime_type := a_type + "/*"
end
ensure
type_assigned: type ~ a_type
end
set_sub_type (a_sub_type: STRING)
-- Set sub_type with `a_sub_type
do
sub_type := a_sub_type
if attached type as t then
mime_type := t + "/" + a_sub_type
else
mime_type := "*/" + a_sub_type
end
ensure
sub_type_assigned: sub_type ~ a_sub_type
end
put (new: STRING; key: STRING)
-- Insert `new' with `key' if there is no other item
-- associated with the same key. If present, replace
-- the old value with `new'
do
if params.has_key (key) then
params.replace (new, key)
else
params.force (new, key)
end
ensure
has_key: params.has_key (key)
has_item: params.has_item (new)
end
feature -- Status Report
out: STRING
-- Representation of the current object
do
create Result.make_from_string ("(")
if attached type as t then
Result.append_string ("'" + t + "',")
end
if attached sub_type as st then
Result.append_string (" '" + st + "',")
end
Result.append_string (" {")
from
params.start
until
params.after
loop
Result.append ("'" + params.key_for_iteration + "':'" + params.item_for_iteration + "',");
params.forth
end
Result.append ("})")
end
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := out
end
feature {NONE} -- Implementation
params: HASH_TABLE [STRING, STRING]
--dictionary of all the parameters for the media range
;note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,30 +0,0 @@
note
description: "Summary description for {SHARED_MIME}."
date: "$Date$"
revision: "$Revision$"
class
SHARED_CONNEG
feature
mime: MIME_PARSE
once
create Result
end
common: COMMON_ACCEPT_HEADER_PARSER
-- Charset and Encoding
once
create Result
end
language: LANGUAGE_PARSE
once
create Result
end
note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,58 +0,0 @@
note
description: "Summary description for {VARIANT_RESULTS}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
VARIANT_RESULTS
feature -- Mime, Language, Charset and Encoding Results
mime_result : detachable STRING
set_mime_result ( a_mime: STRING)
-- set the mime_result with `a_mime'
do
mime_result := a_mime
ensure
set_mime_result: a_mime ~ mime_result
end
language_result : detachable STRING
set_language_result (a_language : STRING)
-- set the language_result with `a_language'
do
language_result := a_language
ensure
set_language : a_language ~ language_result
end
charset_result : detachable STRING
set_charset_result (a_charset : STRING)
-- set the charset_result with `a_charset'
do
charset_result := a_charset
ensure
set_charset : a_charset ~ charset_result
end
encoding_result : detachable STRING
set_encoding_defautl (an_encoding : STRING)
do
encoding_result := an_encoding
ensure
set_encoding : an_encoding ~ encoding_result
end
note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

View File

@@ -1,4 +0,0 @@
*~
EIFGEN* # ignore all files in the EIFGENs/ directory

View File

@@ -1,167 +0,0 @@
note
description: "Summary description for {CONNEG_SERVER_SIDE_TEST}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
CONNEG_SERVER_SIDE_TEST
inherit
EQA_TEST_SET
redefine
on_prepare
end
feature {NONE} -- Events
on_prepare
-- Called after all initializations in `default_create'.
do
create conneg.make ("application/json", "es", "UTF-8", "")
-- set default values
end
feature -- Test routines
test_media_type_negotiation
local
media_variants : MEDIA_TYPE_VARIANT_RESULTS
mime_types_supported : LIST [STRING]
l_types : STRING
do
-- Scenario 1, the server side does not support client preferences
l_types := "application/json,application/xbel+xml,application/xml"
mime_types_supported := l_types.split(',')
media_variants := conneg.media_type_preference (mime_types_supported, "text/html")
assert ("Expected Not Acceptable", not media_variants.is_acceptable)
assert ("Same Value at 1",mime_types_supported.at (1).is_equal (media_variants.supported_variants.at (1)))
assert ("Same count",mime_types_supported.count = media_variants.supported_variants.count)
assert ("Variant header is void",media_variants.variant_header = Void)
assert ("Media type is void",media_variants.media_type = Void)
-- Scenario 2, the client doesnt send values in the header, Accept:
media_variants := conneg.media_type_preference (mime_types_supported, "")
assert ("Expected Acceptable", media_variants.is_acceptable)
assert ("Variants is dettached",media_variants.supported_variants = Void)
assert ("Mime is defaul", conneg.mime_default.is_equal (media_variants.media_type))
assert ("Variant header", media_variants.variant_header = Void)
--Scenario 3, the server select the best match, and set the vary header
media_variants := conneg.media_type_preference (mime_types_supported, "text/*,application/json;q=0.5")
assert ("Expected Acceptable", media_variants.is_acceptable)
assert ("Variants is dettached",media_variants.supported_variants = Void)
assert ("Variant Header", media_variants.variant_header.is_equal ("Accept"))
assert ("Media Type is application/json", media_variants.media_type.is_equal ("application/json"))
end
test_charset_negotiation
local
charset_variants : CHARACTER_ENCODING_VARIANT_RESULTS
charset_supported : LIST [STRING]
l_charset : STRING
do
-- Scenario 1, the server side does not support client preferences
l_charset := "UTF-8, iso-8859-5"
charset_supported := l_charset.split(',')
charset_variants := conneg.charset_preference (charset_supported, "unicode-1-1")
assert ("Expected Not Acceptable", not charset_variants.is_acceptable)
assert ("Same Value at 1",charset_supported.at (1).is_equal (charset_variants.supported_variants.at (1)))
assert ("Same count",charset_supported.count = charset_variants.supported_variants.count)
assert ("Variant header is void",charset_variants.variant_header = Void)
assert ("Character type is void",charset_variants.character_type = Void)
-- Scenario 2, the client doesnt send values in the header, Accept-Charset:
charset_variants := conneg.charset_preference (charset_supported, "")
assert ("Expected Acceptable", charset_variants.is_acceptable)
assert ("Variants is dettached",charset_variants.supported_variants = Void)
assert ("Charset is defaul", conneg.charset_default.is_equal (charset_variants.character_type))
assert ("Variant header", charset_variants.variant_header = Void)
--Scenario 3, the server select the best match, and set the vary header
charset_variants := conneg.charset_preference (charset_supported, "unicode-1-1, UTF-8;q=0.3, iso-8859-5")
assert ("Expected Acceptable", charset_variants.is_acceptable)
assert ("Variants is dettached",charset_variants.supported_variants = Void)
assert ("Variant Header", charset_variants.variant_header.is_equal ("Accept-Charset"))
assert ("Character Type is iso-8859-5", charset_variants.character_type.is_equal ("iso-8859-5"))
end
test_compression_negotiation
local
compression_variants : COMPRESSION_VARIANT_RESULTS
compression_supported : LIST [STRING]
l_compression : STRING
do
-- Scenario 1, the server side does not support client preferences
l_compression := ""
compression_supported := l_compression.split(',')
compression_variants := conneg.encoding_preference (compression_supported, "gzip")
assert ("Expected Not Acceptable", not compression_variants.is_acceptable)
assert ("Same Value at 1",compression_supported.at (1).is_equal (compression_variants.supported_variants.at (1)))
assert ("Same count",compression_supported.count = compression_variants.supported_variants.count)
assert ("Variant header is void",compression_variants.variant_header = Void)
assert ("Compression type is void",compression_variants.compression_type = Void)
-- Scenario 2, the client doesnt send values in the header, Accept-Encoding
compression_variants := conneg.encoding_preference (compression_supported, "")
assert ("Expected Acceptable", compression_variants.is_acceptable)
assert ("Variants is dettached",compression_variants.supported_variants = Void)
assert ("Compression is defaul", conneg.encoding_default.is_equal (compression_variants.compression_type))
assert ("Variant header", compression_variants.variant_header = Void)
--Scenario 3, the server select the best match, and set the vary header
l_compression := "gzip"
compression_supported := l_compression.split(',')
conneg.set_encoding_defautl ("gzip")
compression_variants := conneg.encoding_preference (compression_supported, "compress,gzip;q=0.7")
assert ("Expected Acceptable", compression_variants.is_acceptable)
assert ("Variants is dettached",compression_variants.supported_variants = Void)
assert ("Variant Header", compression_variants.variant_header.is_equal ("Accept-Encoding"))
assert ("Encoding Type is gzip", compression_variants.compression_type.is_equal ("gzip"))
end
test_language_negotiation
local
language_variants : LANGUAGE_VARIANT_RESULTS
languages_supported : LIST [STRING]
l_languages : STRING
do
-- Scenario 1, the server side does not support client preferences
l_languages := "es,en,en-US,fr;q=0.6"
languages_supported := l_languages.split(',')
language_variants := conneg.language_preference (languages_supported, "de")
assert ("Expected Not Acceptable", not language_variants.is_acceptable)
assert ("Same Value at 1",languages_supported.at (1).is_equal (language_variants.supported_variants.at (1)))
assert ("Same count",languages_supported.count = language_variants.supported_variants.count)
assert ("Variant header is void",language_variants.variant_header = Void)
assert ("Language type is void",language_variants.language_type = Void)
-- Scenario 2, the client doesnt send values in the header, Accept-Language:
language_variants := conneg.language_preference (languages_supported, "")
assert ("Expected Acceptable", language_variants.is_acceptable)
assert ("Variants is dettached",language_variants.supported_variants = Void)
assert ("Language is defaul", conneg.language_default.is_equal (language_variants.language_type))
assert ("Variant header", language_variants.variant_header = Void)
--Scenario 3, the server select the best match, and set the vary header
language_variants := conneg.language_preference (languages_supported, "fr,es;q=0.4")
assert ("Expected Acceptable", language_variants.is_acceptable)
assert ("Variants is dettached",language_variants.supported_variants = Void)
assert ("Variant Header", language_variants.variant_header.is_equal ("Accept-Language"))
assert ("Language Type is fr", language_variants.language_type.is_equal ("fr"))
end
feature -- Implementation
conneg : CONNEG_SERVER_SIDE
end

View File

@@ -1,117 +0,0 @@
note
description: "Summary description for {LANGUAGE_PARSER_TEST}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
LANGUAGE_PARSER_TEST
inherit
EQA_TEST_SET
redefine
on_prepare
end
feature {NONE} -- Events
on_prepare
-- Called after all initializations in `default_create'.
do
create parser
end
feature -- Test routines
test_parse_media_range
do
assert ("Expected ('da', {'q':'1.0',})", parser.parse_media_range ("da").out.same_string ("('da', {'q':'1.0',})"));
assert ("Expected ('en', 'gb', {'q':'0.8',})", parser.parse_media_range ("en-gb;q=0.8").out.same_string ("('en', 'gb', {'q':'0.8',})"));
assert ("Expected ('en', {'q':'0.7',})", parser.parse_media_range ("en;q=0.7").out.same_string ("('en', {'q':'0.7',})"));
assert ("Expected ('en', '*', {'q':'1.0',})", parser.parse_media_range ("en-*").out.same_string ("('en', '*', {'q':'1.0',})"));
end
test_RFC2616_example
local
accept : STRING
do
accept := "da, en-gb;q=0.8, en;q=0.7";
assert ("Expected 1.0", 1.0 = parser.quality ("da", accept))
assert ("Expected 0.8", 0.8 = parser.quality ("en-gb", accept))
assert ("Expected 0.8", 0.8 = parser.quality ("en", accept))
assert ("Expected 0.8", 0.8 = parser.quality ("en-*", accept))
end
test_best_match
local
mime_types_supported : LIST [STRING]
l_types : STRING
do
l_types := "en-gb,en-us"
mime_types_supported := l_types.split(',')
assert ("Expected en-us", parser.best_match (mime_types_supported, "en-us").same_string ("en-us"))
assert ("Direct match with a q parameter", parser.best_match (mime_types_supported, "en-gb;q=1").same_string ("en-gb"))
assert ("Direct match second choice with a q parameter", parser.best_match (mime_types_supported, "en-us;q=1").same_string ("en-us"))
assert ("Direct match using a subtype wildcard", parser.best_match (mime_types_supported, "en-*;q=1").is_equal ("en-gb"))
assert ("Match using a type wildcard", parser.best_match (mime_types_supported, "*").same_string ("en-gb"))
l_types := "en-gb,es"
mime_types_supported := l_types.split(',')
assert ("Match using a type versus a lower weighted subtype", parser.best_match (mime_types_supported, "es-*;q=0.5,*;q=0.1").same_string ("es"))
assert ("Fail to match anything",parser.best_match (mime_types_supported, "fr; q=0.9").same_string (""))
l_types := "en-gb,en-us"
mime_types_supported := l_types.split(',')
assert ("Test 1 verify fitness ordering", parser.best_match (mime_types_supported, "en-gb,en-us,*").same_string ("en-gb"))
l_types := "es,en-gb;q=1.0,fr;q=0.6"
mime_types_supported := l_types.split(',')
assert ("Match default es at first position", parser.best_match (mime_types_supported, "es;q=1.0,*;q=0.1,fr").same_string ("es"))
l_types := "en-gb;q=1.0,fr;q=0.6,es"
mime_types_supported := l_types.split(',')
assert ("Match default es at last position", parser.best_match (mime_types_supported, "es;q=1.0,*;q=0.1,fr").same_string ("es"))
l_types := "en-gb;q=1.0,fr,es"
mime_types_supported := l_types.split(',')
assert ("Match first top quality and fitness", parser.best_match (mime_types_supported, "es;q=1.0,*;q=0.1,fr").same_string ("es"))
l_types := "fr;q=1.0,en,es"
mime_types_supported := l_types.split(',')
assert ("Test 1", parser.best_match (mime_types_supported, "es;q=1.0,*/*;q=0.1,en;q=0.9").same_string ("es"))
l_types := "fr;q=1.0,en,es"
mime_types_supported := l_types.split(',')
assert ("Test 1", parser.best_match (mime_types_supported, "es,*/*;q=0.1,en").same_string ("es"))
l_types := "fr;q=1.0,en,es"
mime_types_supported := l_types.split(',')
assert ("Test 2", parser.best_match (mime_types_supported, "en,es,*/*;q=0.1").same_string ("en"))
l_types := "es,en;q=0.6"
mime_types_supported := l_types.split(',')
assert ("Test 2", parser.best_match (mime_types_supported, "fr;q=1.0, en;q=0.6, es").same_string ("es"))
end
test_support_wildcard
local
mime_types_supported : LIST[STRING]
l_types : STRING
do
l_types := "en-*,fr"
mime_types_supported := l_types.split(',')
assert ("match using a type wildcard", parser.best_match (mime_types_supported, "en-gb").same_string ("en-*"))
end
parser : LANGUAGE_PARSE
end

View File

@@ -0,0 +1,31 @@
CONNEG is a library that provides utilities to select the best repesentation of a resource for a client where there are multiple representations available.
Using this library you can retrieve the best variant for media type, language preference, charset, and enconding/compression.
Take into account that the library is under development so is expected that the API change.
The library contains utilities that deal with content negotiation (server driven negotiation).This utility class
is based on ideas taken from the Book Restful WebServices Cookbook
The class SERVER_CONTENT_NEGOTIATION contains several features that helps to write different types of negotiation (media type, language,
charset and compression).
So for each of the following questions, you will have a corresponding method to help in the solution.
- How to implement Media type negotiation?
Hint: Use SERVER_CONTENT_NEGOTIATION.media_type_preference
or SERVER_MEDIA_TYPE_NEGOTIATION.preference
- How to implement Language Negotiation?
Hint: Use SERVER_CONTENT_NEGOTIATION.language_preference
or SERVER_LANGUAGE_NEGOTIATION.preference
- How to implement Character Negotiation?
Hint: Use SERVER_CONTENT_NEGOTIATION.charset_preference
or SERVER_CHARSET_NEGOTIATION.preference
- How to implement Encoding Negotiation?
Hint: Use SERVER_CONTENT_NEGOTIATION.encoding_preference
or SERVER_ENCODING_NEGOTIATION.preference
There is also a [test case](test/conneg_server_side_test.e "conneg_server_side_test") where you can check how to use this class.

View File

@@ -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>
@@ -12,7 +12,12 @@
<assertions precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="http" location="..\http\http-safe.ecf"/>
<cluster name="conneg" location=".\src\" recursive="true"/>
<library name="http" location="..\http\http-safe.ecf" readonly="false"/>
<cluster name="conneg" location=".\src\" recursive="true">
<file_rule>
<exclude>/implementation</exclude>
</file_rule>
</cluster>
<cluster name="conneg_imp" location=".\src\implementation\" recursive="true" hidden="true"/>
</target>
</system>

View File

@@ -13,6 +13,12 @@
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="http" location="../http/http.ecf"/>
<cluster name="conneg" location=".\src" recursive="true"/>
<cluster name="conneg" location=".\src\" recursive="true">
<file_rule>
<exclude>/implementation</exclude>
</file_rule>
</cluster>
<cluster name="conneg_imp" location=".\src\implementation" recursive="true" hidden="true">
</cluster>
</target>
</system>

View 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

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {FITNESS_AND_QUALITY}."
author: ""
description: "FITNESS_AND_QUALITY. Object holding a fitness/quality values."
date: "$Date$"
revision: "$Revision$"
@@ -21,13 +20,15 @@ create
feature -- Initialization
make (a_fitness: INTEGER; a_quality: REAL_64)
-- Create an object with `a_fitness' and `a_quality'
do
fitness := a_fitness
quality := a_quality
create mime_type.make_empty
create {STRING_8} entity.make_empty
ensure
fitness_assigned : fitness = a_fitness
quality_assigned : quality = a_quality
entity_empty: entity.is_empty
end
feature -- Access
@@ -36,17 +37,17 @@ feature -- Access
quality: REAL_64
mime_type: STRING
entity: READABLE_STRING_8
-- optionally used
-- empty by default
--| Could be a mime type, an encoding, ...
feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
create Result.make_from_string (mime_type)
create Result.make_from_string (entity)
Result.append (" (")
Result.append ("quality=" + quality.out)
Result.append (" ; fitness=" + fitness.out)
@@ -55,12 +56,12 @@ feature -- Status report
feature -- Element Change
set_mime_type (a_mime_type: STRING)
-- set mime_type with `a_mime_type'
set_entity (a_entity: READABLE_STRING_8)
-- set `entity' with `a_entity'
do
mime_type := a_mime_type
entity := a_entity
ensure
mime_type_assigned : mime_type.same_string (a_mime_type)
entity_assigned : entity.same_string (a_entity)
end
feature -- Comparision
@@ -75,7 +76,7 @@ feature -- Comparision
end
end
note
copyright: "2011-2011, Javier Velilla, Jocelyn Fiat and others"
copyright: "2011-2013, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
end

Some files were not shown because too many files have changed in this diff Show More