Compare commits

...

59 Commits

Author SHA1 Message Date
Jocelyn Fiat
34c6288032 Fixed a last minute regression due to removal REQUEST.chunked_input 2012-04-13 17:19:14 +02:00
Jocelyn Fiat
21b03a05fd Added WSF_ROUTER.pre_route_execution_actions: ACTION_SEQUENCE [like route]
This way, one can add logger hook to router, to see which "route" was taken by the request.
2012-04-13 16:40:19 +02:00
Jocelyn Fiat
0bd2d16c12 Made WGI_CHUNKED_INPUT_STREAM inherits from WGI_INPUT_STREAM
Merged REQUEST.input and REQUEST.chunked_input
  Now REQUEST.input handles directly the chunked transfer encoding, or the non chunked.
Kept REQUEST.is_chunked_input since it matters that Content-Length is 0 even if there are input (chunked) data.
2012-04-13 16:33:49 +02:00
Jocelyn Fiat
e6a727ee42 Fixed compilation of samples 2012-04-12 12:51:52 +02:00
Jocelyn Fiat
1403cc5c09 Fixed compilation 2012-04-12 12:25:34 +02:00
Jocelyn Fiat
3bbf356f19 Missing commit related to changes on WSF_ROUTER 2012-04-12 11:59:14 +02:00
Jocelyn Fiat
b541efcc8f Now WGI_RESPONSE.set_status_code (..) has a new argument to pass optional custom reason phrase.
This is a minor breaking change (but prior to the first release, so acceptable)
   And then it is now possible to precise a custom reason phrase (useful for 4xx and 5xx response)

At the WSF_RESPONSE level, the status code is now sent only when the header are sent.
thus, it is possible to change the status code as long as no header is sent.
(in the future, we should also try to delay the sending of headers)

Removed WGI_RESPONSE.put_header_lines (..) which was not used, and WGI is not meant to provide such user friendly features
Now this is available directly on WSF_RESPONSE
2012-04-12 11:19:41 +02:00
Jocelyn Fiat
082def2b70 Merge branch 'master' of github.com:EiffelWebFramework/EWF 2012-04-06 15:52:03 +02:00
Jocelyn Fiat
79607600e6 updated to EiffelWebFramework/EWF 2012-04-06 16:27:22 +03:00
Jocelyn Fiat
0b6b7f793c sync with json lib. 2012-04-06 11:31:57 +02:00
Jocelyn Fiat
badc2458c4 Sync with wiki 2012-04-06 11:29:07 +02:00
Jocelyn Fiat
d4208c59f3 Use https://github.com/EiffelWebFramework/EWF.git as master 2012-04-06 11:21:50 +02:00
Jocelyn Fiat
4bafa5b3c0 Added `transfered_content_length' to WSF_RESPONSE to provide the information to application
This can be used to build logs for instance.
2012-04-05 21:15:12 +02:00
Jocelyn Fiat
c89b19371e Relaxed WSF_REDIRECTION_RESPONSE.set_content (.., ..) to allow Void for content type
in order to use the one set in header or the default one.
2012-04-05 21:14:10 +02:00
Jocelyn Fiat
10ebc12852 Removed default handler for WSF_ROUTER
Added 	WSF_ROUTE to replace a TUPLE [H, C]
	WSF_ROUTER.route (req): detachable WSF_ROUTE
	WSF_ROUTER.execute_route (a_route, req, res)
	To help usage of Routers
Remove WSF_HANDLER_CONTEXT obsolete features.
Added comments
2012-04-05 21:13:04 +02:00
Jocelyn Fiat
593e48ec5b Merge remote-tracking branch 'remotes/eiffelworld/master' 2012-04-02 09:29:53 +02:00
Jocelyn Fiat
11b15ec5b7 Merge pull request #10 from oligot/unneeded_precondition
Unneeded precondition
2012-04-02 00:28:23 -07:00
Olivier Ligot
ff713a42ab [REM] Remove unneeded precondition 2012-04-02 09:28:22 +02:00
Olivier Ligot
155c45be6c [IMP] Ignore *.swp files 2012-04-02 09:28:10 +02:00
Jocelyn Fiat
09fa1adaab removed obsolete message. 2012-04-02 09:27:59 +02:00
Olivier Ligot
425c276051 [REM] Remove unneeded precondition 2012-03-27 11:30:42 +02:00
Olivier Ligot
0040e4b0d0 [IMP] Ignore *.swp files 2012-03-27 11:29:33 +02:00
Olivier Ligot
b862065c04 Merge branch 'master', remote branch 'upstream/master' 2012-03-26 17:19:02 +02:00
Jocelyn Fiat
874677ab7a Renamed same_media_type as same_simple_type
Added comments
2012-03-23 19:00:49 +01:00
Jocelyn Fiat
ed200b93dd updated tests.ecf 2012-03-23 18:40:29 +01:00
Jocelyn Fiat
bcccfb22ed Added HTTP_MEDIA_TYPE (maybe it will just replace the HTTP_CONTENT_TYPE later)
renamed .media_type as .simple_type for now
  allow more than one parameters
2012-03-23 18:39:19 +01:00
Jocelyn Fiat
5c98d7ba4e Use media_type as replacement for type_and_subtype_string in HTTP_CONTENT_TYPE 2012-03-23 16:49:13 +01:00
Jocelyn Fiat
40c6aff423 Added class HTTP_CONTENT_TYPE to help manipulation of Content-Type value
Now WSF_REQUEST return a HTTP_CONTENT_TYPE if available
Adapted WSF_MIME_HANDLER to use this new class
Added one manual autotest to test MIME handler
2012-03-23 16:40:13 +01:00
Jocelyn Fiat
ac9cbb0bd2 in WSF_RESPONSE, put_header' now call put_header_text'
Removed unused local variable
2012-03-21 14:49:09 +01:00
Jocelyn Fiat
95c3bbf6e5 Fixed very bad mistake where no Result was ever set for WSF_REQUEST.item (..) 2012-03-21 14:43:32 +01:00
Jocelyn Fiat
b955912dc2 fixed compilation issue (typo) 2012-03-20 16:17:43 +01:00
Jocelyn Fiat
50223b12f7 Do not try to compile_all in "dev" folder 2012-03-20 16:15:16 +01:00
Jocelyn Fiat
6c7ba93062 Reverted a previous change, we should not truncated Content-Type after ;
In the case of multipart/form-data  the parameter "boundary=" is essential
2012-03-20 14:35:04 +01:00
Jocelyn Fiat
743f26c376 Use WSF_DEFAULT_SERVICE for the test echo server 2012-03-20 12:18:44 +01:00
Jocelyn Fiat
d256ec3944 Fixing compilation of specific example using the WGI connector directly 2012-03-20 12:15:45 +01:00
Jocelyn Fiat
482f8e41e7 Added WSF_SERVICE.to_wgi_service to ease direct integration with existing WGI components 2012-03-20 11:40:13 +01:00
Jocelyn Fiat
9eef812795 Relaxed access to `send_to', now it is exported again to avoid breaking existing code. 2012-03-20 11:38:44 +01:00
Jocelyn Fiat
86fcaa2835 remove unused local variable 2012-03-20 11:15:14 +01:00
Jocelyn Fiat
897aeb3132 WSF_REQUEST.content_type should keep only the relevant part of the content type
and forget about the eventual parameters (charset, name) ...

  note: it is possible to query meta_string_variable ("CONTENT_TYPE")
        to get the complete Content-Type header
2012-03-20 11:12:18 +01:00
Jocelyn Fiat
48acdea73c Added HTTP_HEADER.(put|add)_content_type_with_parameters (...) 2012-03-20 11:08:52 +01:00
Jocelyn Fiat
cbaae12156 removed obsolete 2012-03-20 10:30:04 +01:00
Jocelyn Fiat
8344607eb6 Implemented WSF_RESPONSE.put_error (...) and related
Added WSF_RESPONSE.put_character
Renamed  WGI_OUTPUT_STREAM.put_character_8 as put_character  to follow style of put_string  (and not put_string_8)
Refactored the WSF_DEFAULT_SERVICE_LAUNCHER
Added WSF_DEFAULT_SERVICE to be more user friendly
Splitted the wsf/default/ libraries to have wsf/connector/... and being able to handle more than one connector in the same application
2012-03-20 10:29:55 +01:00
Jocelyn Fiat
71d5dc4795 Moved mime handler classes under wsf/src/mime/ 2012-03-20 08:38:38 +01:00
Jocelyn Fiat
3f0b745ecc removed unwanted rescue clause 2012-03-19 15:20:29 +01:00
Jocelyn Fiat
3432e2d8b2 Updating EWSGI specification classes 2012-03-19 15:06:50 +01:00
Jocelyn Fiat
fea0f115a0 Removed WGI_RESPONSE.write (..)
Replaced any internal call to WGI_RESPONSE.write () by the associated implementation (i.e  output.put_string (...)  )
Added WGI_OUTPUT_STREAM.put_crlf

Renamed WSF_RESPONSE.put_response (a_message) as  `send (a_message)'
WSF_RESPONSE_MESSAGE.send_to (res)  is now exported only to WSF_RESPONSE
2012-03-19 14:52:12 +01:00
Berend de Boer
84a12447db Avoid another indirection. 2012-03-19 14:02:13 +01:00
Berend de Boer
876f9e02b7 status must be set, else WGI_SERVICE.execute will report the
postcondition violation.

Conflicts:

	library/server/wsf/router/wsf_handler.e
2012-03-19 13:58:17 +01:00
Berend de Boer
e5323dd208 Minor code cleanup/typo fix. 2012-03-19 13:54:48 +01:00
Berend de Boer
77834a3dd8 Move wgi_service spec to its own directory else I get a class
conflicts with compile_ise.ecf generated by gexace.
2012-03-19 13:54:34 +01:00
Jocelyn Fiat
4906345a62 Improved comment in WSF_RESPONSE.put_response (..)
Added WSF_REDIRECTION_RESPONSE class
2012-03-19 12:32:12 +01:00
Jocelyn Fiat
487487ad44 Added WSF_RESPONSE_HANDLER based on WSF_RESPONSE_MESSAGE
The descendant has to implement the function

    response (ctx: C; req: WSF_REQUEST): WSF_RESPONSE_MESSAGE

Added related features and class in WSF_ROUTER to be able to use agent easily.
2012-03-19 12:04:46 +01:00
Jocelyn Fiat
ef5ba19c46 Refactored WSF_HANDLER_CONTEXT
- removed path_parameter
  - added `item' to include WSF_REQUEST.item
  - marked obsolete `parameter'

The goal is to remove confusion, remove URI_TEMPLATE specific `path_parameter'
and provide a way to use ctx.item (..) to also include meta variable, query, form, ... items
2012-03-19 10:21:29 +01:00
Jocelyn Fiat
b05ff01262 Use local variable to speed up access to `input' 2012-03-19 10:12:06 +01:00
Jocelyn Fiat
9f1940c46d Applied wsf_extension creation, and classes moved from wsf to wsf_extension 2012-03-16 15:17:22 +01:00
Jocelyn Fiat
f69ff42564 Created wsf_extension, and moved some classes from wsf to wsf_extension
WSF_HANDLER_HELPER
   WSF_RESOURCE_HANDLER_HELPER
   WSF_HANDLER_ROUTES_RECORDER
2012-03-16 14:12:02 +01:00
Jocelyn Fiat
eb3e9f2186 applied removal of HTTP_HEADER.put_status (..) 2012-03-16 13:53:22 +01:00
Jocelyn Fiat
03b10bdc14 Removed HTTP_HEADER.put_status (...)
It is not recommended to send the status code as part of the HTTP Header,
  so let's remove this ambiguity and do not encourage EWF user to use it
2012-03-16 13:35:52 +01:00
Jocelyn Fiat
46eb92ac37 Major renaming, adopt the WSF_ prefix for all classes under "wsf", and simplify some class names
Removed in WGI_INPUT_STREAM, the assertion "same_last_string_reference"
Copyright updates
2012-03-16 09:49:41 +01:00
202 changed files with 4087 additions and 1726 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
EIFGENs
tests/temp/
.svn/
*.swp

4
.gitmodules vendored
View File

@@ -1,12 +1,12 @@
[submodule "doc/wiki"]
path = doc/wiki
url = https://github.com/Eiffel-World/Eiffel-Web-Framework.wiki.git
url = https://github.com/EiffelWebFramework/EWF.wiki.git
[submodule "contrib/library/server/nino"]
path = contrib/library/server/nino
url = https://github.com/Eiffel-World/EiffelWebNino.git
[submodule "contrib/library/text/parser/json"]
path = contrib/library/text/parser/json
url = https://github.com/Eiffel-World/ejson-svn.git
url = https://github.com/Eiffel-World/json.git
[submodule "contrib/ise_library/cURL"]
path = contrib/ise_library/cURL
url = https://github.com/EiffelSoftware/mirror-Eiffel-cURL.git

View File

@@ -5,11 +5,11 @@
Official project site for Eiffel Web Framework:
* http://eiffel-world.github.com/Eiffel-Web-Framework/
* http://eiffelwebframework.github.com/EWF/
For more information please have a look at the related wiki:
* https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki
* https://github.com/EiffelWebFramework/EWF/wiki
## Requirements
@@ -20,10 +20,10 @@ For more information please have a look at the related wiki:
## How to get the source code?
Using git version >= 1.6.5
* git clone --recursive https://github.com/Eiffel-World/Eiffel-Web-Framework.git
* git clone --recursive https://github.com/EiffelWebFramework/EWF.git
Otherwise, try
* git clone https://github.com/Eiffel-World/Eiffel-Web-Framework.git
* git clone https://github.com/EiffelWebFramework/EWF.git
* cd Eiffel-Web-Framework
* git submodule update --init
* git submodule foreach --recursive git checkout master
@@ -77,4 +77,4 @@ An alternative to the last 2 instructions is to use the script from tools folder
For more information please have a look at the related wiki:
* https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki
* https://github.com/EiffelWebFramework/EWF/wiki

View File

@@ -11,6 +11,7 @@
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="wsf" location="..\..\..\..\..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
<library name="wsf_extension" location="..\..\..\..\..\library\server\wsf_extension\wsf_extension-safe.ecf" readonly="false"/>
<library name="http" location="..\..\..\..\..\library\protocol\http\http-safe.ecf"/>
<library name="uri_template" location="..\..\..\..\..\library\protocol\uri_template\uri_template-safe.ecf"/>
<cluster name="contrib" location=".\src\contrib\" recursive="true">

View File

@@ -10,6 +10,7 @@
<option warning="true" full_class_checking="true"/>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="wsf" location="..\..\..\..\..\library\server\wsf\wsf.ecf"/>
<library name="wsf_extension" location="..\..\..\..\..\library\server\wsf_extension\wsf_extension.ecf" readonly="false"/>
<library name="http" location="..\..\..\..\..\library\protocol\http\http.ecf"/>
<library name="uri_template" location="..\..\..\..\..\library\protocol\uri_template\uri_template.ecf"/>
<cluster name="contrib" location=".\src\contrib\" recursive="true">

View File

@@ -34,6 +34,13 @@ feature -- Access
do
end
resource_value (ctx: C): detachable READABLE_STRING_32
do
if attached {WSF_STRING} ctx.item ("resource") as s then
Result := s.string
end
end
feature -- Execution
execute_application (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
@@ -50,8 +57,7 @@ feature -- Execution
create s.make_empty
if
attached {WSF_STRING} ctx.path_parameter ("resource") as l_resource_value and then
attached l_resource_value.string as l_resource
attached resource_value (ctx) as l_resource
then
from
hdl_cursor := router.new_cursor
@@ -309,7 +315,7 @@ feature -- Access
end
note
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
copyright: "Copyright (c) 1984-2012, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -8,7 +8,7 @@ class
REST_REQUEST_AGENT_HANDLER [C -> REST_REQUEST_HANDLER_CONTEXT]
inherit
REQUEST_AGENT_HANDLER [C]
WSF_AGENT_HANDLER [C]
rename
execute as execute_application
end

View File

@@ -8,7 +8,9 @@ deferred class
REST_REQUEST_HANDLER [C -> REST_REQUEST_HANDLER_CONTEXT]
inherit
REQUEST_HANDLER [C]
WSF_HANDLER [C]
WSF_HANDLER_HELPER
feature -- Access

View File

@@ -8,7 +8,7 @@ deferred class
REST_REQUEST_HANDLER_CONTEXT
inherit
REQUEST_HANDLER_CONTEXT
WSF_HANDLER_CONTEXT
feature -- Accept: Content-Type
@@ -73,7 +73,7 @@ feature -- Format
request_accepted_format (a_format_variable_name: detachable READABLE_STRING_8; a_supported_content_types: detachable ARRAY [READABLE_STRING_8]): detachable READABLE_STRING_8
-- Format id for the request based on {HTTP_FORMAT_CONSTANTS}
do
if a_format_variable_name /= Void and then attached string_parameter (a_format_variable_name) as ctx_format then
if a_format_variable_name /= Void and then attached string_item (a_format_variable_name) as ctx_format then
Result := ctx_format.as_string_8
else
Result := request_format_from_content_type (request_accepted_content_type (a_supported_content_types))

View File

@@ -8,7 +8,7 @@ deferred class
REST_REQUEST_ROUTER [H -> REST_REQUEST_HANDLER [C], C -> REST_REQUEST_HANDLER_CONTEXT]
inherit
REQUEST_ROUTER [H, C]
WSF_ROUTER [H, C]
;note
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"

View File

@@ -8,7 +8,7 @@ deferred class
REST_SERVICE_I [H -> REST_REQUEST_HANDLER [C], C -> REST_REQUEST_HANDLER_CONTEXT]
inherit
ROUTED_SERVICE_I [H, C]
WSF_ROUTED_SERVICE_I [H, C]
redefine
router
end

View File

@@ -1,5 +1,5 @@
note
description: "Summary description for {REQUEST_URI_HANDLER_CONTEXT}."
description: "Summary description for {WSF_URI_HANDLER_CONTEXT}."
author: ""
date: "$Date$"
revision: "$Revision$"
@@ -8,7 +8,7 @@ class
REST_REQUEST_URI_HANDLER_CONTEXT
inherit
REQUEST_URI_HANDLER_CONTEXT
WSF_URI_HANDLER_CONTEXT
REST_REQUEST_HANDLER_CONTEXT

View File

@@ -8,7 +8,7 @@ class
REST_REQUEST_URI_ROUTER_I [H -> REST_REQUEST_HANDLER [C], C -> REST_REQUEST_URI_HANDLER_CONTEXT create make end]
inherit
REQUEST_URI_ROUTER_I [H, C]
WSF_URI_ROUTER_I [H, C]
REST_REQUEST_ROUTER [H, C]

View File

@@ -1,5 +1,5 @@
note
description: "Summary description for {REQUEST_ROUTING_HANDLER}."
description: "Summary description for {WSF_ROUTING_HANDLER }."
author: ""
date: "$Date$"
revision: "$Revision$"
@@ -9,7 +9,7 @@ class
C -> REST_REQUEST_URI_HANDLER_CONTEXT create make end]
inherit
REQUEST_URI_ROUTING_HANDLER_I [H, C]
WSF_URI_ROUTING_HANDLER_I [H, C]
redefine
router,
execute
@@ -38,7 +38,7 @@ feature -- Execution
execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
do
Precursor {REQUEST_URI_ROUTING_HANDLER_I} (ctx, req, res)
Precursor {WSF_URI_ROUTING_HANDLER_I} (ctx, req, res)
end
execute_application (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)

View File

@@ -1,5 +1,5 @@
note
description: "Summary description for {REQUEST_URI_TEMPLATE_HANDLER_CONTEXT}."
description: "Summary description for {WSF_URI_TEMPLATE_HANDLER_CONTEXT}."
author: ""
date: "$Date$"
revision: "$Revision$"
@@ -8,7 +8,7 @@ class
REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT
inherit
REQUEST_URI_TEMPLATE_HANDLER_CONTEXT
WSF_URI_TEMPLATE_HANDLER_CONTEXT
REST_REQUEST_HANDLER_CONTEXT
@@ -16,7 +16,7 @@ create
make
note
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
copyright: "Copyright (c) 1984-2012, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -8,7 +8,7 @@ class
REST_REQUEST_URI_TEMPLATE_ROUTER_I [H -> REST_REQUEST_HANDLER [C], C -> REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT create make end]
inherit
REQUEST_URI_TEMPLATE_ROUTER_I [H, C]
WSF_URI_TEMPLATE_ROUTER_I [H, C]
REST_REQUEST_ROUTER [H, C]

View File

@@ -1,5 +1,5 @@
note
description: "Summary description for {REQUEST_ROUTING_HANDLER}."
description: "Summary description for {WSF_ROUTING_HANDLER }."
author: ""
date: "$Date$"
revision: "$Revision$"
@@ -9,7 +9,7 @@ class
C -> REST_REQUEST_URI_TEMPLATE_HANDLER_CONTEXT create make end]
inherit
REQUEST_URI_TEMPLATE_ROUTING_HANDLER_I [H, C]
WSF_URI_TEMPLATE_ROUTING_HANDLER_I [H, C]
redefine
router,
execute
@@ -40,7 +40,7 @@ feature -- Execution
execute (ctx: C; req: WSF_REQUEST; res: WSF_RESPONSE)
do
pre_execute (ctx, req, res)
Precursor {REQUEST_URI_TEMPLATE_ROUTING_HANDLER_I} (ctx, req, res)
Precursor {WSF_URI_TEMPLATE_ROUTING_HANDLER_I} (ctx, req, res)
post_execute (ctx, req, res)
end

View File

@@ -59,7 +59,7 @@ feature -- Execution
s.append_string (" format=" + l_format + "%N")
end
if attached ctx.string_parameter ("op") as l_op then
if attached ctx.string_item ("op") as l_op then
s.append_string (" op=" + l_op)
if l_op.same_string ("crash") then
(create {DEVELOPER_EXCEPTION}).raise

View File

@@ -50,7 +50,6 @@ feature {NONE} -- Handlers
create gh.make (4)
router.map ("/test", gh)
gh.map_default (h)
-- gh.map ("/test", h)
gh.map ("/test/{op}", h)
gh.map ("/test.{format}", h)

View File

@@ -10,7 +10,7 @@ feature -- Access
local
cgi: WGI_CGI_CONNECTOR
do
create cgi.make (Current)
create cgi.make (to_wgi_service)
cgi.launch
end

View File

@@ -10,9 +10,9 @@ feature -- Access
local
libfcgi: WGI_LIBFCGI_CONNECTOR
do
create libfcgi.make (Current)
create libfcgi.make (to_wgi_service)
libfcgi.launch
end
end
gateway_name: STRING = "libFCGI"
@@ -20,7 +20,7 @@ feature -- Access
do
(create {EXCEPTIONS}).die (a_code)
end
note
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"

View File

@@ -18,7 +18,7 @@ feature -- Access
print ("Example: start a Nino web server on port " + port_number.out +
", %Nand reply Hello World for any request such as http://localhost:" + port_number.out + "/" + base_url + "%N")
end
create app.make_custom (agent wgi_execute, base_url)
create app.make_custom (to_wgi_service, base_url)
app.force_single_threaded
app.listen (port_number)

View File

@@ -84,7 +84,7 @@ feature -- Helpers
end
rep_data.set_message (s)
end
rep_data.send (res)
res.send (rep_data)
rep_data.recycle
end

View File

@@ -25,6 +25,7 @@
<library name="json" location="..\..\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
<library name="uri_template" location="..\..\library\protocol\uri_template\uri_template-safe.ecf" readonly="false"/>
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf" readonly="false"/>
<library name="wsf_extension" location="..\..\library\server\wsf_extension\wsf_extension-safe.ecf" readonly="false"/>
<cluster name="src" location="src\" recursive="true"/>
</target>
</system>

View File

@@ -5,10 +5,10 @@ note
revision: "$Revision$"
class
ORDER_HANDLER [C -> REQUEST_HANDLER_CONTEXT]
ORDER_HANDLER [C -> WSF_HANDLER_CONTEXT]
inherit
REQUEST_HANDLER [C]
REQUEST_RESOURCE_HANDLER_HELPER [C]
WSF_HANDLER [C]
WSF_RESOURCE_HANDLER_HELPER [C]
redefine
do_get,
do_post,
@@ -82,7 +82,6 @@ feature -- HTTP Methods
do
create h.make
create etag_utils
h.put_status ({HTTP_STATUS_CODE}.ok)
h.put_content_type_application_json
if attached {JSON_VALUE} json.value (l_order) as jv then
l_msg := jv.representation
@@ -166,7 +165,6 @@ feature -- HTTP Methods
json.add_converter(joc)
create h.make
h.put_status ({HTTP_STATUS_CODE}.ok)
h.put_content_type_application_json
if attached req.request_time as time then
h.add_header ("Date:" +time.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT")
@@ -212,10 +210,9 @@ feature -- HTTP Methods
h : HTTP_HEADER
do
create h.make
h.put_status ({HTTP_STATUS_CODE}.no_content)
h.put_content_type_application_json
if attached req.request_time as time then
h.put_utc_date (time)
h.put_utc_date (time)
end
res.set_status_code ({HTTP_STATUS_CODE}.no_content)
res.put_header_text (h.string)
@@ -254,7 +251,6 @@ feature -- HTTP Methods
create joc.make
json.add_converter(joc)
h.put_status ({HTTP_STATUS_CODE}.created)
h.put_content_type_application_json
if attached {JSON_VALUE} json.value (l_order) as jv then
l_msg := jv.representation

View File

@@ -10,9 +10,11 @@ class
inherit
ANY
URI_TEMPLATE_ROUTED_SERVICE
WSF_URI_TEMPLATE_ROUTED_SERVICE
ROUTED_SERVICE_HELPER
WSF_HANDLER_HELPER
WSF_DEFAULT_SERVICE
create
make
@@ -20,13 +22,13 @@ create
feature {NONE} -- Initialization
make
local
s: DEFAULT_SERVICE_LAUNCHER
do
initialize_router
create s.make_and_launch_with_options (agent execute, <<["port", 9090]>>)
set_service_option ("port", 9090)
make_and_launch
end
create_router
do
create router.make (2)
@@ -34,7 +36,7 @@ feature {NONE} -- Initialization
setup_router
local
order_handler: ORDER_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT]
order_handler: ORDER_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT]
do
create order_handler
router.map_with_request_methods ("/order", order_handler, <<"POST">>)
@@ -56,7 +58,6 @@ feature -- Execution
req.input.read_string (req.content_length_value.as_integer_32)
end
create h.make
h.put_status ({HTTP_STATUS_CODE}.method_not_allowed)
h.put_content_type_text_plain
l_api_doc := "%NPlease check the API%NURI:/order METHOD: POST%NURI:/order/{orderid} METHOD: GET, PUT, DELETE%N"
l_description := req.request_method + req.request_uri + " is not allowed" + "%N" + l_api_doc

View File

@@ -6,19 +6,14 @@ note
class
APPLICATION
inherit
WSF_DEFAULT_SERVICE
create
make
make_and_launch
feature {NONE} -- Initialization
make
-- Run application.
local
s: DEFAULT_SERVICE_LAUNCHER
do
create s.make_and_launch (agent execute)
end
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
do
-- To send a response we need to setup, the status code and

View File

@@ -1,20 +1,48 @@
<?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="simple" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486">
<target name="simple">
<root class="APPLICATION" feature="make"/>
<target name="common" abstract="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" 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>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf"/>
<library name="http" location="..\..\library\protocol\http\http-safe.ecf"/>
<library name="wsf" location="..\..\library\server\wsf\wsf-safe.ecf"/>
<cluster name="simple" location=".\" recursive="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
</cluster>
</target>
<target name="simple_nino" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" 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>
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf"/>
<cluster name="simple" location=".\" recursive="true"/>
</target>
<target name="simple_cgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" 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>
<library name="default_cgi" location="..\..\library\server\wsf\default\cgi-safe.ecf"/>
<cluster name="simple" location=".\" recursive="true"/>
</target>
<target name="simple_libfcgi" extends="common">
<root class="APPLICATION" feature="make_and_launch"/>
<option warning="true" 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>
<library name="default_libfcgi" location="..\..\library\server\wsf\default\libfcgi-safe.ecf"/>
<cluster name="simple" location=".\" recursive="true"/>
</target>
<target name="simple" extends="simple_nino">
</target>
</system>

View File

@@ -6,19 +6,14 @@ note
class
SERVICE_FILE
inherit
WSF_DEFAULT_SERVICE
create
make
make_and_launch
feature {NONE} -- Initialization
make
-- Run application.
local
s: DEFAULT_SERVICE_LAUNCHER
do
create s.make_and_launch (agent execute)
end
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
local
f: WSF_FILE_RESPONSE

View File

@@ -1,7 +1,7 @@
<?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="service_file" uuid="C28C4F53-9963-46C0-A080-8F13E94E7486">
<target name="service_file">
<root class="SERVICE_FILE" feature="make"/>
<root class="SERVICE_FILE" feature="make_and_launch"/>
<option warning="true" 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>

View File

@@ -10,9 +10,9 @@ class
inherit
ANY
URI_TEMPLATE_ROUTED_SERVICE
WSF_URI_TEMPLATE_ROUTED_SERVICE
ROUTED_SERVICE_HELPER
WSF_DEFAULT_SERVICE
create
make
@@ -21,13 +21,14 @@ feature {NONE} -- Initialization
make
-- Initialize Current
local
s: DEFAULT_SERVICE_LAUNCHER
do
initialize_router
create s.make_and_launch (agent execute)
-- Use the following line to use particular port number (as 9090) with Nino connector
-- create s.make_and_launch_with_options (agent execute, <<["port", 9090]>>)
-- To use particular port number (as 9090) with Nino connector
-- Uncomment the following line
-- set_service_option ("port", 9090)
make_and_launch
end
create_router
@@ -39,7 +40,7 @@ feature {NONE} -- Initialization
setup_router
-- Setup router
local
www: REQUEST_FILE_SYSTEM_HANDLER [REQUEST_URI_TEMPLATE_HANDLER_CONTEXT]
www: WSF_FILE_SYSTEM_HANDLER [WSF_URI_TEMPLATE_HANDLER_CONTEXT]
do
router.map_agent ("/upload{?nb}", agent execute_upload)
@@ -84,13 +85,13 @@ feature -- Execution
res.redirect_now_with_content (req.script_url ("/"), "Redirection to " + req.script_url ("/"), "text/html")
end
execute_not_found (uri: READABLE_STRING_8; ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE)
execute_not_found (uri: READABLE_STRING_8; ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE)
-- `uri' is not found, redirect to default page
do
res.redirect_now_with_content (req.script_url ("/"), uri + ": not found.%NRedirection to " + req.script_url ("/"), "text/html")
end
execute_upload (ctx: REQUEST_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE)
execute_upload (ctx: WSF_URI_TEMPLATE_HANDLER_CONTEXT; req: WSF_REQUEST; res: WSF_RESPONSE)
-- Upload page is requested, either GET or POST
-- On GET display the web form to upload file, by passing ?nb=5 you can upload 5 images
-- On POST display the uploaded files
@@ -128,7 +129,7 @@ feature -- Execution
n := n - 1
end
l_body.append (" <input type=%"submit%" value=%"Upload%"/>%N</form>")
page.send_to (res)
res.send (page)
else
create l_body.make (255)
l_body.append ("<h1>EWF: Uploaded files</h1>%N")
@@ -156,7 +157,7 @@ feature -- Execution
page.set_title ("EWF: uploaded image")
page.add_style ("../style.css", "all")
page.set_body (l_body)
page.send_to (res)
res.send (page)
end
end

View File

@@ -0,0 +1,10 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"

View File

@@ -13,4 +13,14 @@ feature -- Status
deferred
end
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -34,4 +34,14 @@ feature -- Auth type
Auth_type_any: INTEGER = 3
Auth_type_anysafe: INTEGER = 4
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -92,6 +92,11 @@ feature -- Authentication
Result := session.credentials
end
proxy: detachable TUPLE [host: READABLE_STRING_8; port: INTEGER]
do
Result := session.proxy
end
feature -- Settings
timeout: INTEGER
@@ -131,6 +136,12 @@ feature -- Settings
Result := session.default_response_charset
end
is_insecure: BOOLEAN
-- Allow connections to SSL sites without certs
do
Result := session.is_insecure
end
feature {NONE} -- Utilities
append_parameters_to_url (a_url: STRING; a_parameters: detachable ARRAY [detachable TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
@@ -198,4 +209,14 @@ feature {NONE} -- Utilities: encoding
Result.replace_substring_all ("\\", "\")
end
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -101,4 +101,14 @@ feature -- Element change
end
end
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -164,4 +164,14 @@ feature {NONE} -- Implementation
internal_headers: detachable ARRAYED_LIST [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]]
-- Internal cached value for the headers
;note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -105,6 +105,12 @@ feature -- Settings
default_response_charset: detachable READABLE_STRING_8
-- Default encoding of responses. Used if no charset is provided by the host.
is_insecure: BOOLEAN
-- Allow connections to SSL sites without certs
proxy: detachable TUPLE [host: READABLE_STRING_8; port: INTEGER]
-- Proxy information [`host' and `port']
feature -- Access
base_url: READABLE_STRING_8
@@ -132,9 +138,9 @@ feature -- Change
base_url := u
end
set_timeout (n: like timeout)
set_timeout (n_seconds: like timeout)
do
timeout := n
timeout := n_seconds
end
set_connect_timeout (n: like connect_timeout)
@@ -147,6 +153,11 @@ feature -- Change
add_header ("User-Agent", v)
end
set_is_insecure (b: BOOLEAN)
do
is_insecure := b
end
add_header (k: READABLE_STRING_8; v: READABLE_STRING_8)
do
headers.force (v, k)
@@ -203,4 +214,23 @@ feature -- Change
max_redirects := n
end
set_proxy (a_host: detachable READABLE_STRING_8; a_port: INTEGER)
do
if a_host = Void then
proxy := Void
else
proxy := [a_host, a_port]
end
end
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -81,11 +81,11 @@ feature {NONE} -- Implementation
note
library: "cURL: Library of reusable components for Eiffel."
copyright: "Copyright (c) 1984-2006, Eiffel Software and others"
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, 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
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

View File

@@ -27,4 +27,14 @@ feature -- Status
create Result.make (a_base_url)
end
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -54,6 +54,7 @@ feature -- Execution
curl_easy: CURL_EASY_EXTERNALS
curl_handle: POINTER
ctx: like context
l_proxy: like proxy
do
ctx := context
curl := session.curl
@@ -83,7 +84,14 @@ feature -- Execution
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_header, 1)
--| PROXY ...
if ctx /= Void and then attached ctx.proxy as l_proxy then
if ctx /= Void then
l_proxy := ctx.proxy
end
if l_proxy = Void then
l_proxy := proxy
end
if l_proxy /= Void then
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_proxyport, l_proxy.port)
curl_easy.setopt_string (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_proxy, l_proxy.host)
end
@@ -104,6 +112,12 @@ feature -- Execution
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_followlocation, 0)
end
--| SSL
if is_insecure then
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_ssl_verifyhost, 0)
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_ssl_verifypeer, 0)
end
if request_method.is_case_insensitive_equal ("GET") then
curl_easy.setopt_integer (curl_handle, {CURL_OPT_CONSTANTS}.curlopt_httpget, 1)
elseif request_method.is_case_insensitive_equal ("POST") then
@@ -253,4 +267,14 @@ feature {NONE} -- Implementation
end
end
end
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -121,4 +121,14 @@ feature {LIBCURL_HTTP_CLIENT_REQUEST} -- Curl implementation
-- cURL easy externals
;note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -1,5 +1,5 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, Eiffel Software and others"
copyright: "2011-${YEAR}, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -1,4 +1,4 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, Javier Velilla, Jocelyn Fiat and others"
copyright: "2011-${YEAR}, Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -1,5 +1,5 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, Eiffel Software and others"
copyright: "2011-${YEAR}, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -0,0 +1,32 @@
note
description: "[
This class is to represent the CONTENT_TYPE value
]"
date: "$Date$"
revision: "$Revision$"
class
HTTP_CONTENT_TYPE
inherit
HTTP_MEDIA_TYPE
create
make,
make_from_string
convert
make_from_string ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8}),
string: {READABLE_STRING_8}
note
copyright: "2011-2012, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -12,7 +12,6 @@ note
(or HTTP_CONSTANTS which groups them for convenience)
Note the return status code is not part of the HTTP header
However you can set the "Status: " header line if you want
]"
legal: "See notice at end of class."
status: "See notice at end of class."
@@ -25,16 +24,12 @@ class
inherit
ANY
HTTP_STATUS_CODE_MESSAGES --| useful for `put_status'
export
{NONE} all
end
create
make,
make_with_count,
make_from_array,
make_from_header
make_from_header,
make_from_raw_header_data
convert
make_from_array ({ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]]}),
@@ -72,6 +67,27 @@ feature {NONE} -- Initialization
append_header_object (a_header)
end
make_from_raw_header_data (h: READABLE_STRING_8)
-- Create Current from raw header data
local
line : detachable STRING
lines: LIST [READABLE_STRING_8]
do
lines := h.split ('%N')
make_with_count (lines.count)
across
lines as c
loop
line := c.item
if not line.is_empty then
if line [line.count] = '%R' then
line.remove_tail (1)
end
add_header (line)
end
end
end
feature -- Recycle
recycle
@@ -106,6 +122,21 @@ feature -- Access
result_has_single_ending_cr_lf: Result.count >= 4 implies not Result.substring (Result.count - 3, Result.count).same_string ("%R%N%R%N")
end
to_name_value_iterable: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]]
local
res: ARRAYED_LIST [TUPLE [READABLE_STRING_8, READABLE_STRING_8]]
do
create res.make (headers.count)
across
headers as c
loop
if attached header_name_value (c.item) as tu then
res.extend (tu)
end
end
Result := res
end
feature -- Header: filling
append_array (a_headers: ARRAY [TUPLE [key: READABLE_STRING_8; value: READABLE_STRING_8]])
@@ -128,7 +159,7 @@ feature -- Header: filling
loop
add_header (c.item.string)
end
end
end
feature -- Header change: general
@@ -147,7 +178,7 @@ feature -- Header change: general
require
h_not_empty: not h.is_empty
do
force_header_by_name (header_name (h), h)
force_header_by_name (header_name_colon (h), h)
end
add_header_key_value (k,v: READABLE_STRING_8)
@@ -162,22 +193,6 @@ feature -- Header change: general
put_header (k + colon_space + v)
end
feature -- Status related
put_status (c: INTEGER)
-- Put "Status: " header
-- Rarely used
local
s: STRING
do
create s.make_from_string (c.out)
if attached http_status_code_message (c) as msg then
s.append_character (' ')
s.append (msg)
end
put_header_key_value ("Status", s)
end
feature -- Content related header
put_content_type (t: READABLE_STRING_8)
@@ -191,26 +206,76 @@ feature -- Content related header
add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t)
end
put_content_type_with_parameters (t: READABLE_STRING_8; a_params: detachable ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
local
s: STRING_8
do
if a_params /= Void and then not a_params.is_empty then
create s.make_from_string (t)
across
a_params as p
loop
if attached p.item as nv then
s.append_character (';')
s.append_character (' ')
s.append (nv.name)
s.append_character ('=')
s.append_character ('%"')
s.append (nv.value)
s.append_character ('%"')
end
end
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, s)
else
put_content_type (t)
end
end
add_content_type_with_parameters (t: READABLE_STRING_8; a_params: detachable ARRAY [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
local
s: STRING_8
do
if a_params /= Void and then not a_params.is_empty then
create s.make_from_string (t)
across
a_params as p
loop
if attached p.item as nv then
s.append_character (';')
s.append_character (' ')
s.append (nv.name)
s.append_character ('=')
s.append_character ('%"')
s.append (nv.value)
s.append_character ('%"')
end
end
add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, s)
else
add_content_type (t)
end
end
put_content_type_with_charset (t: READABLE_STRING_8; c: READABLE_STRING_8)
do
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t + "; charset=" + c + "")
put_content_type_with_parameters (t, <<["charset", c]>>)
end
add_content_type_with_charset (t: READABLE_STRING_8; c: READABLE_STRING_8)
-- same as `put_content_type_with_charset', but allow multiple definition of "Content-Type"
do
add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t + "; charset=" + c + "")
add_content_type_with_parameters (t, <<["charset", c]>>)
end
put_content_type_with_name (t: READABLE_STRING_8; n: READABLE_STRING_8)
do
put_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t + "; name=%"" + n + "%"")
put_content_type_with_parameters (t, <<["name", n]>>)
end
add_content_type_with_name (t: READABLE_STRING_8; n: READABLE_STRING_8)
-- same as `put_content_type_with_name', but allow multiple definition of "Content-Type"
do
add_header_key_value ({HTTP_HEADER_NAMES}.header_content_type, t + "; name=%"" + n + "%"")
add_content_type_with_parameters (t, <<["name", n]>>)
end
put_content_length (n: INTEGER)
@@ -309,6 +374,7 @@ feature -- Content-type helpers
put_content_type_multipart_form_data do put_content_type ({HTTP_MIME_TYPES}.multipart_form_data) end
put_content_type_multipart_signed do put_content_type ({HTTP_MIME_TYPES}.multipart_signed) end
put_content_type_multipart_encrypted do put_content_type ({HTTP_MIME_TYPES}.multipart_encrypted) end
put_content_type_application_x_www_form_encoded do put_content_type ({HTTP_MIME_TYPES}.application_x_www_form_encoded) end
feature -- Date
@@ -500,7 +566,7 @@ feature {NONE} -- Implementation: Header
force_header_by_name (n: detachable READABLE_STRING_8; h: READABLE_STRING_8)
-- Add header `h' or replace existing header of same header name `n'
require
h_has_name_n: (n /= Void and attached header_name (h) as hn) implies n.same_string (hn)
h_has_name_n: (n /= Void and attached header_name_colon (h) as hn) implies n.same_string (hn)
local
l_headers: like headers
do
@@ -523,7 +589,7 @@ feature {NONE} -- Implementation: Header
end
end
header_name (h: READABLE_STRING_8): detachable READABLE_STRING_8
header_name_colon (h: READABLE_STRING_8): detachable STRING_8
-- If any, header's name with colon
--| ex: for "Foo-bar: something", this will return "Foo-bar:"
local
@@ -552,6 +618,36 @@ feature {NONE} -- Implementation: Header
Result := s
end
header_name_value (h: READABLE_STRING_8): detachable TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]
-- If any, header's [name,value]
--| ex: for "Foo-bar: something", this will return ["Foo-bar", "something"]
local
s: detachable STRING_8
i,n: INTEGER
c: CHARACTER
do
from
i := 1
n := h.count
create s.make (10)
until
i > n or c = ':' or s = Void
loop
c := h[i]
inspect c
when ':' then
when '-', 'a' .. 'z', 'A' .. 'Z' then
s.extend (c)
else
s := Void
end
i := i + 1
end
if s /= Void then
Result := [s, h.substring (i, n)]
end
end
feature {NONE} -- Implementation
append_line_to (s: READABLE_STRING_8; h: STRING_8)
@@ -566,7 +662,7 @@ feature {NONE} -- Implementation
h.append_character ('%N')
end
date_to_rfc1123_http_date_format (dt: DATE_TIME): READABLE_STRING_8
date_to_rfc1123_http_date_format (dt: DATE_TIME): STRING_8
-- String representation of `dt' using the RFC 1123
do
Result := dt.formatted_out ("ddd,[0]dd mmm yyyy [0]hh:[0]mi:[0]ss.ff2") + " GMT"
@@ -581,7 +677,7 @@ feature {NONE} -- Constants
semi_colon_space: STRING = "; "
note
copyright: "2011-2012, Eiffel Software and others"
copyright: "2011-2012, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -231,6 +231,9 @@ feature -- Request or Response header name
-- Implementation-specific headers that may have various effects anywhere along the request-response chain.
--| Example: Pragma: no-cache
header_status: STRING = "Status"
-- CGI program can use this to return the HTTP status code to the client.
header_via: STRING = "Via"
-- Request: Informs the server of proxies through which the request was sent.
-- Response: Informs the client of proxies through which the response was sent.
@@ -245,7 +248,7 @@ feature -- MIME related
header_content_transfer_encoding: STRING = "Content-Transfer-Encoding"
note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2012, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -0,0 +1,350 @@
note
description: "[
This class is to represent a media type
the Internet Media Type [9] of the attached entity if the type
was provided via a "Content-type" field in the wgi_request header,
or if the server can determine it in the absence of a supplied
"Content-type" field. The syntax is the same as for the HTTP
"Content-Type" header field.
CONTENT_TYPE = "" | media-type
media-type = type "/" subtype *( ";" parameter)
type = token
subtype = token
parameter = attribute "=" value
attribute = token
value = token | quoted-string
The type, subtype, and parameter attribute names are not
case-sensitive. Parameter values MAY be case sensitive. Media
types and their use in HTTP are described in section 3.7 of
the HTTP/1.1 specification [8].
Example:
application/x-www-form-urlencoded
application/x-www-form-urlencoded; charset=UTF8
]"
date: "$Date$"
revision: "$Revision$"
class
HTTP_MEDIA_TYPE
inherit
DEBUG_OUTPUT
create
make,
make_from_string
convert
make_from_string ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8}),
string: {READABLE_STRING_8}
feature {NONE} -- Initialization
make (a_type, a_subtype: READABLE_STRING_8)
-- Create Current based on `a_type/a_subtype'
require
not a_type.is_empty
not a_subtype.is_empty
do
type := a_type
subtype := a_subtype
ensure
has_no_error: not has_error
end
make_from_string (s: READABLE_STRING_8)
-- Create Current from `s'
-- if `s' does not respect the expected syntax, has_error is True
local
t: STRING_8
i,n: INTEGER
p: INTEGER
do
-- Ignore starting space (should not be any)
from
i := 1
n := s.count
until
i > n or not s[i].is_space
loop
i := i + 1
end
if i < n then
-- Look for semi colon as parameter separation
p := s.index_of (';', i)
if p > 0 then
t := s.substring (i, p - 1)
i := p + 1
p := s.index_of (';', i)
if p = 0 then
add_parameter_from_string (s, i, n)
i := n
else
add_parameter_from_string (s, i, p - 1)
i := p + 1
end
else
t := s.substring (i, n)
end
-- Remove eventual trailing space
t.right_adjust
-- Extract type and subtype
p := t.index_of ('/', 1)
if p = 0 then
has_error := True
type := t
subtype := ""
else
subtype := t.substring (p + 1, t.count)
type := t
t.keep_head (p - 1)
end
else
has_error := True
type := ""
subtype := type
end
ensure
not has_error implies (create {HTTP_CONTENT_TYPE}.make_from_string (string)).same_string (string)
end
feature -- Status report
has_error: BOOLEAN
-- Current has error?
--| Mainly in relation with `make_from_string'
feature -- Access
type: READABLE_STRING_8
-- Main type
subtype: READABLE_STRING_8
-- Sub type
has_parameter (a_name: READABLE_STRING_8): BOOLEAN
-- Has Current a parameter?
do
if attached parameters as plst then
Result := plst.has (a_name)
end
end
parameter (a_name: READABLE_STRING_8): detachable READABLE_STRING_8
-- Value for eventual parameter named `a_name'.
do
if attached parameters as plst then
Result := plst.item (a_name)
end
end
parameters: detachable HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
-- Parameters
feature -- Conversion
string: READABLE_STRING_8
-- String representation of type/subtype; attribute=value
local
res: like internal_string
do
res := internal_string
if res = Void then
create res.make_from_string (simple_type)
if attached parameters as plst then
across
plst as p
loop
res.append_character (';')
res.append_character (' ')
res.append (p.key)
res.append_character ('=')
res.append_character ('%"')
res.append (p.item)
res.append_character ('%"')
end
end
internal_string := res
end
Result := res
end
simple_type: READABLE_STRING_8
-- String representation of type/subtype
local
res: like internal_simple_type
s: like subtype
do
res := internal_simple_type
if res = Void then
create res.make_from_string (type)
s := subtype
if not s.is_empty then
check has_error: has_error end
-- Just in case not is_valid, we keep in `type' the original string
res.append_character ('/')
res.append (s)
end
internal_simple_type := res
end
Result := res
end
feature -- Status report
same_as (other: HTTP_CONTENT_TYPE): BOOLEAN
-- Current has same type/subtype and parameters as `other'?
local
plst,oplst: like parameters
do
Result := other.type.same_string (other.type) and then
other.subtype.same_string (other.subtype)
if Result then
plst := parameters
oplst := other.parameters
if plst = oplst then
elseif plst = Void then
Result := False -- since oplst /= Void
elseif oplst /= Void and then plst.count = oplst.count then
across
plst as p
until
not Result
loop
Result := attached oplst.item (p.key) as op_value and then p.item.same_string (op_value)
end
else
Result := False
end
end
end
same_simple_type (s: READABLE_STRING_8): BOOLEAN
-- Current has same type/subtype string representation as `s'?
do
Result := simple_type.same_string (s)
end
same_string (s: READABLE_STRING_8): BOOLEAN
-- Current has same string representation as `s'?
do
Result := string.same_string (s)
end
feature -- Element change
add_parameter (a_name: READABLE_STRING_8; a_value: READABLE_STRING_8)
-- Set parameter for `a_name' to `a_value'
local
plst: like parameters
do
plst := parameters
if plst = Void then
create plst.make (1)
parameters := plst
end
plst.force (a_value, a_name)
internal_string := Void
end
remove_parameter (a_name: READABLE_STRING_8)
-- Remove parameter named `a_name'
do
if attached parameters as plst then
plst.prune (a_name)
if plst.is_empty then
parameters := Void
end
end
internal_string := Void
end
feature {NONE} -- Implementation
add_parameter_from_string (s: READABLE_STRING_8; start_index, end_index: INTEGER)
-- Add parameter from string " attribute=value "
local
pn,pv: STRING_8
i: INTEGER
p: INTEGER
err: BOOLEAN
do
-- Skip spaces
from
i := start_index
until
i > end_index or not s[i].is_space
loop
i := i + 1
end
if i < end_index then
p := s.index_of ('=', i)
if p > 0 and p < end_index then
pn := s.substring (i, p - 1)
pv := s.substring (p + 1, end_index)
pv.right_adjust
if pv.count > 0 and pv [1] = '%"' then
if pv [pv.count] = '%"' then
pv := pv.substring (2, pv.count - 1)
else
err := True
-- missing closing double quote.
end
end
if not err then
add_parameter (pn, pv)
end
else
-- expecting: attribute "=" value
err := True
end
end
has_error := has_error or err
end
feature {NONE} -- Internal
internal_string: detachable STRING_8
internal_simple_type: detachable STRING_8
feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
if type /= Void and subtype /= Void then
Result := type + "/" + subtype
if attached parameters as plst then
across
plst as p
loop
Result.append ("; " + p.key + "=" + "%"" + p.item + "%"")
end
end
else
Result := ""
end
end
invariant
type_and_subtype_not_empty: not has_error implies not type.is_empty and not subtype.is_empty
note
copyright: "2011-2012, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -94,7 +94,7 @@ feature -- 5xx : Server Error
user_access_denied: INTEGER = 530
note
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
copyright: "2011-2012, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -148,7 +148,7 @@ feature -- Status messages
end
note
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
copyright: "2011-2012, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -1,5 +1,5 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, Eiffel Software and others"
copyright: "2011-${YEAR}, Jocelyn Fiat, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -176,6 +176,13 @@ feature -- Builder
end
end
expanded_string_with_base_url (a_base_url: READABLE_STRING_8; a_ht: HASH_TABLE [detachable ANY, STRING]): STRING
-- Expanded template using variable from `a_ht'
-- with based url
do
Result := a_base_url + expanded_string (a_ht)
end
feature -- Match
match (a_uri: READABLE_STRING_8): detachable URI_TEMPLATE_MATCH_RESULT
@@ -506,7 +513,7 @@ feature {NONE} -- Implementation
end
note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2012, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -94,7 +94,7 @@ feature {NONE} -- Implementation
end
;note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2012, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -42,13 +42,13 @@ feature -- Execution
do
if not rescued then
create req.make ((create {EXECUTION_ENVIRONMENT}).starting_environment_variables, create {WGI_CGI_INPUT_STREAM}.make, Current)
create res.make (create {WGI_CGI_OUTPUT_STREAM}.make)
create res.make (create {WGI_CGI_OUTPUT_STREAM}.make, create {WGI_CGI_ERROR_STREAM}.make)
service.execute (req, res)
else
if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.exception_trace as l_trace then
if res /= Void then
if not res.status_is_set then
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error)
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void)
end
if res.message_writable then
res.put_string ("<pre>" + l_trace + "</pre>")

View File

@@ -0,0 +1,57 @@
note
description: "Summary description for WGI_CGI_ERROR_STREAM."
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
class
WGI_CGI_ERROR_STREAM
inherit
WGI_ERROR_STREAM
CONSOLE
rename
make as console_make
end
create
make
feature {NONE} -- Initialization
make
do
make_open_stdout ("stderr")
end
feature -- Error
put_error (a_message: READABLE_STRING_8)
do
put_readable_string_8 (a_message)
end
put_readable_string_8 (s: READABLE_STRING_8)
-- Write `s' at end of default output.
local
ext: C_STRING
do
if s.count > 0 then
create ext.make (s)
console_ps (file_pointer, ext.managed_data.item, s.count)
end
end
note
copyright: "2011-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -36,21 +36,24 @@ feature {NONE} -- Initialization
feature -- Status writing
put_status_line (a_code: INTEGER)
-- Put status code line for `a_code'
--| Note this is a default implementation, and could be redefined
--| for instance in relation to NPH CGI script
put_status_line (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8)
-- <Precursor>
local
s: STRING
m: detachable READABLE_STRING_8
do
if a_code /= 200 then
create s.make (16)
s.append ("Status:")
s.append_character (' ')
s.append_integer (a_code)
if attached http_status_code_message (a_code) as l_status_message then
m := a_reason_phrase
if m = Void then
m := http_status_code_message (a_code)
end
if m /= Void then
s.append_character (' ')
s.append_string (l_status_message)
s.append_string (m)
end
put_header_line (s)
end

View File

@@ -20,8 +20,8 @@ feature {NONE} -- Initialization
do
service := a_service
create fcgi.make
create {WGI_LIBFCGI_INPUT_STREAM} input.make (fcgi)
create {WGI_LIBFCGI_OUTPUT_STREAM} output.make (fcgi)
create input.make (fcgi)
create output.make (fcgi)
end
feature -- Access
@@ -63,13 +63,13 @@ feature -- Execution
do
if not rescued then
create req.make (vars, a_input, Current)
create res.make (a_output)
create res.make (a_output, a_output)
service.execute (req, res)
else
if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.exception_trace as l_trace then
if res /= Void then
if not res.status_is_set then
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error)
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error, Void)
end
if res.message_writable then
res.put_string ("<pre>" + l_trace + "</pre>")
@@ -84,10 +84,10 @@ feature -- Execution
feature -- Input/Output
input: WGI_INPUT_STREAM
input: WGI_LIBFCGI_INPUT_STREAM
-- Input from client (from httpd server via FCGI)
output: WGI_OUTPUT_STREAM
output: WGI_LIBFCGI_OUTPUT_STREAM
-- Output to client (via httpd server/fcgi)
feature {NONE} -- Implementation

View File

@@ -75,6 +75,7 @@ feature -- Access
last_string: STRING
-- Last string read
-- <Precursor>
last_character: CHARACTER_8
-- Last item read

View File

@@ -11,6 +11,8 @@ class
inherit
WGI_OUTPUT_STREAM
WGI_ERROR_STREAM
HTTP_STATUS_CODE_MESSAGES
export
{NONE} all
@@ -38,23 +40,24 @@ feature -- Status report
feature -- Status writing
put_status_line (a_code: INTEGER)
-- Put status code line for `a_code'
--| Note this is a default implementation, and could be redefined
--| for instance in relation to NPH CGI script
put_status_line (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8)
-- <Precursor>
local
s: STRING
m: detachable READABLE_STRING_8
do
--| Do not send any Status line back to the FastCGI client
--| According to http://www.fastcgi.com/docs/faq.html#httpstatus
if a_code /= 200 then
create s.make (16)
s.append ("Status:")
s.append_character (' ')
s.append_integer (a_code)
if attached http_status_code_message (a_code) as l_status_message then
m := a_reason_phrase
if m = Void then
m := http_status_code_message (a_code)
end
if m /= Void then
s.append_character (' ')
s.append_string (l_status_message)
s.append_string (m)
end
put_header_line (s)
end
@@ -68,6 +71,12 @@ feature -- Basic operation
fcgi.put_string (s)
end
put_character (c: CHARACTER_8)
-- Send `c' to http client
do
fcgi.put_string (c.out)
end
feature -- Basic operations
flush
@@ -75,6 +84,13 @@ feature -- Basic operations
do
end
feature -- Error
put_error (a_message: READABLE_STRING_8)
do
fcgi.put_error (a_message)
end
feature {NONE} -- Implementation
fcgi: FCGI

View File

@@ -1,5 +1,5 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, Eiffel Software and others"
copyright: "2011-${YEAR}, 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

@@ -8,17 +8,33 @@ class
create
make,
make_custom
make_custom,
make_with_callback,
make_custom_with_callback
feature {NONE} -- Implementation
make (a_callback: like {WGI_AGENT_SERVICE}.callback)
make (a_service: WGI_SERVICE)
-- Initialize `Current'.
do
make_custom (a_callback, Void)
make_custom (a_service, Void)
end
make_custom (a_callback: like {WGI_AGENT_SERVICE}.callback; a_base_url: detachable STRING)
make_custom (a_service: WGI_SERVICE; a_base_url: detachable STRING)
-- Initialize `Current'.
require
base_url_starts_with_slash: (a_base_url /= Void and then not a_base_url.is_empty) implies a_base_url.starts_with ("/")
do
create connector.make_with_base (a_service, a_base_url)
end
make_with_callback (a_callback: like {WGI_AGENT_SERVICE}.callback)
-- Initialize `Current'.
do
make_custom_with_callback (a_callback, Void)
end
make_custom_with_callback (a_callback: like {WGI_AGENT_SERVICE}.callback; a_base_url: detachable STRING)
-- Initialize `Current'.
require
base_url_starts_with_slash: (a_base_url /= Void and then not a_base_url.is_empty) implies a_base_url.starts_with ("/")
@@ -26,7 +42,7 @@ feature {NONE} -- Implementation
app: WGI_AGENT_SERVICE
do
create app.make (a_callback)
create connector.make_with_base (app, a_base_url)
make_custom (app, a_base_url)
end
feature -- Access
@@ -88,7 +104,7 @@ feature -- Server
end
note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -1,6 +1,5 @@
note
description: "Summary description for {WGI_NINO_CONNECTOR}."
author: ""
date: "$Date$"
revision: "$Revision$"
@@ -120,14 +119,14 @@ feature -- Server
res: detachable WGI_NINO_RESPONSE_STREAM
do
create req.make (env, create {WGI_NINO_INPUT_STREAM}.make (a_socket), Current)
create res.make (create {WGI_NINO_OUTPUT_STREAM}.make (a_socket))
create res.make (create {WGI_NINO_OUTPUT_STREAM}.make (a_socket), Void)
req.set_meta_string_variable ("RAW_HEADER_DATA", a_headers_text)
service.execute (req, res)
res.commit
end
note
copyright: "2011-2012, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -36,21 +36,27 @@ feature -- Input
read_character
-- Read the next character in input stream.
-- Make the result available in `last_character'.
local
src: like source
do
if source.socket_ok then
source.read_character
last_character := source.last_character
src := source
if src.socket_ok then
src.read_character
last_character := src.last_character
else
last_character := '%U'
end
end
read_string (nb: INTEGER)
local
src: like source
do
src := source
last_string.wipe_out
if source.socket_ok then
source.read_stream_thread_aware (nb)
last_string.append_string (source.last_string)
if src.socket_ok then
src.read_stream_thread_aware (nb)
last_string.append_string (src.last_string)
end
end
@@ -58,7 +64,7 @@ feature -- Access
last_string: STRING_8
-- Last string read
-- (Note: this query always return the same object.
-- (Note: this query *might* return the same object.
-- Therefore a clone should be used if the result
-- is to be kept beyond the next call to this feature.
-- However `last_string' is not shared between input objects.)
@@ -81,7 +87,7 @@ feature -- Status report
end
;note
copyright: "2011-2012, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -10,9 +10,6 @@ class
inherit
WGI_OUTPUT_STREAM
redefine
put_character_8
end
HTTP_STATUS_CODE_MESSAGES
export
@@ -40,20 +37,23 @@ feature {WGI_NINO_CONNECTOR, WGI_SERVICE} -- Nino
feature -- Status writing
put_status_line (a_code: INTEGER)
-- Put status code line for `a_code'
--| Note this is a default implementation, and could be redefined
--| for instance in relation to NPH CGI script
put_status_line (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8)
-- <Precursor>
local
s: STRING
m: detachable READABLE_STRING_8
do
create s.make (16)
s.append ({HTTP_CONSTANTS}.http_version_1_1)
s.append_character (' ')
s.append_integer (a_code)
if attached http_status_code_message (a_code) as l_status_message then
m := a_reason_phrase
if m = Void then
m := http_status_code_message (a_code)
end
if m /= Void then
s.append_character (' ')
s.append_string (l_status_message)
s.append_string (m)
end
put_header_line (s)
end
@@ -66,7 +66,7 @@ feature -- Output
target.put_readable_string_8 (s)
end
put_character_8 (c: CHARACTER_8)
put_character (c: CHARACTER_8)
do
target.put_character (c)
end
@@ -86,7 +86,7 @@ feature -- Basic operations
end
note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -21,19 +21,24 @@ create
feature -- Header output operation
put_header_text (a_text: READABLE_STRING_8)
local
o: like output
do
write (a_text)
o := output
o.put_string (a_text)
-- Nino does not support persistent connection for now
write ("Connection: close")
write (crlf)
o.put_string ("Connection: close")
o.put_crlf
-- end of headers
write (crlf)
o.put_crlf
header_committed := True
end
;note
copyright: "2011-2012, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -14,9 +14,8 @@ create
feature {NONE} -- Initialization
make (a_service: like service)
make
do
service := a_service
end
feature -- Access
@@ -27,42 +26,14 @@ feature -- Access
Version: STRING_8 = "0.1"
-- Version of Current connector
feature {NONE} -- Access
service: WGI_SERVICE
-- Gateway Service
feature -- Execution
launch
local
req: WGI_REQUEST_FROM_TABLE
res: detachable WGI_RESPONSE_STREAM
rescued: BOOLEAN
do
if not rescued then
create req.make ((create {EXECUTION_ENVIRONMENT}).starting_environment_variables, create {WGI_NULL_INPUT_STREAM}.make, Current)
create res.make (create {WGI_NULL_OUTPUT_STREAM}.make)
service.execute (req, res)
else
if attached (create {EXCEPTION_MANAGER}).last_exception as e and then attached e.exception_trace as l_trace then
if res /= Void then
if not res.status_is_set then
res.set_status_code ({HTTP_STATUS_CODE}.internal_server_error)
end
if res.message_writable then
res.put_string ("<pre>" + l_trace + "</pre>")
end
end
end
end
rescue
rescued := True
retry
end
note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2012, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -0,0 +1,89 @@
note
description: "Summary description for WGI_NULL_FILE_INPUT_STREAM."
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
class
WGI_NULL_FILE_INPUT_STREAM
inherit
WGI_NULL_INPUT_STREAM
create
make
feature {NONE} -- Initialization
make (f: FILE)
do
file := f
end
file: FILE
feature -- Input
read_character
-- Read the next character in input stream.
-- Make the result available in `last_character'
do
file.read_character
end
read_string (nb: INTEGER)
-- Read the next `nb' characters and
-- make the string result available in `last_string'
do
file.read_stream (nb)
end
feature -- Access
last_string: STRING_8
-- Last string read.
--
-- Note: this query *might* return the same object.
-- Therefore a clone should be used if the result
-- is to be kept beyond the next call to this feature.
-- However `last_string' is not shared between file objects.)
do
Result := file.last_string
end
last_character: CHARACTER_8
-- Last item read.
do
Result := file.last_character
end
feature -- Status report
is_open_read: BOOLEAN
-- Can items be read from input stream?
do
Result := file.is_open_read
end
end_of_input: BOOLEAN
-- Has the end of input stream been reached?
do
Result := file.end_of_file
end
invariant
note
copyright: "2011-2012, 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

@@ -5,31 +5,12 @@ note
date: "$Date$"
revision: "$Revision$"
class
deferred class
WGI_NULL_INPUT_STREAM
inherit
WGI_INPUT_STREAM
undefine
read_to_string
end
CONSOLE
rename
make as console_make,
read_stream as read_string,
end_of_file as end_of_input
end
create
make
feature {NONE} -- Initialization
make
do
make_open_stdin ("stdin")
end
note
copyright: "2011-2011, Eiffel Software and others"

View File

@@ -36,21 +36,24 @@ feature {NONE} -- Initialization
feature -- Status writing
put_status_line (a_code: INTEGER)
-- Put status code line for `a_code'
--| Note this is a default implementation, and could be redefined
--| for instance in relation to NPH NULL script
put_status_line (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8)
-- <Precursor>
local
s: STRING
m: detachable READABLE_STRING_8
do
if a_code /= 200 then
create s.make (16)
s.append ("Status:")
s.append_character (' ')
s.append_integer (a_code)
if attached http_status_code_message (a_code) as l_status_message then
m := a_reason_phrase
if m = Void then
m := http_status_code_message (a_code)
end
if m /= Void then
s.append_character (' ')
s.append_string (l_status_message)
s.append_string (m)
end
put_header_line (s)
end

View File

@@ -0,0 +1,86 @@
note
description: "Summary description for WGI_NULL_STRING_INPUT_STREAM."
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
class
WGI_NULL_STRING_INPUT_STREAM
inherit
WGI_NULL_INPUT_STREAM
create
make
feature {NONE} -- Initialization
make (s: READABLE_STRING_8)
do
body := s
index := 1
count := s.count
last_string := ""
end
body: READABLE_STRING_8
index: INTEGER
count: INTEGER
feature -- Input
read_character
-- Read the next character in input stream.
-- Make the result available in `last_character'
do
last_character := body[index]
index := index + 1
end
read_string (nb: INTEGER)
-- Read the next `nb' characters and
-- make the string result available in `last_string'
local
e: INTEGER
do
e := (index + nb).min (count)
last_string := body.substring (index, e)
index := e + 1
end
feature -- Access
last_string: STRING_8
last_character: CHARACTER_8
feature -- Status report
is_open_read: BOOLEAN
-- Can items be read from input stream?
do
Result := True
end
end_of_input: BOOLEAN
-- Has the end of input stream been reached?
do
Result := index > count
end
invariant
note
copyright: "2011-2012, 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

@@ -18,5 +18,7 @@
<cluster name="specification_request" location="specification\request" recursive="true"/>
<cluster name="specification_response" location="specification\response" recursive="true"/>
<cluster name="specification_connector" location="specification\connector" recursive="true"/>
<cluster name="specification_service" location="specification\service" recursive="true"/>
<cluster name="specification_stream" location="specification\stream" recursive="true"/>
</target>
</system>

View File

@@ -18,5 +18,7 @@
<cluster name="specification_request" location="specification\request" recursive="true"/>
<cluster name="specification_response" location="specification\response" recursive="true"/>
<cluster name="specification_connector" location="specification\connector" recursive="true"/>
<cluster name="specification_service" location="specification\service" recursive="true"/>
<cluster name="specification_stream" location="specification\stream" recursive="true"/>
</target>
</system>

View File

@@ -7,6 +7,9 @@ note
class
HELLO_WORLD
inherit
WGI_SERVICE
create
make
@@ -15,20 +18,20 @@ feature {NONE} -- Initialization
make
do
print ("Example: start a Nino web server on port " + port_number.out + ", %Nand reply Hello World for any request such as http://localhost:8123/%N")
(create {NINO_SERVICE}.make_custom (agent execute, "")).listen (port_number)
(create {NINO_SERVICE}.make_custom (Current, "")).listen (port_number)
end
execute (req: WGI_REQUEST; res: WGI_RESPONSE)
do
res.set_status_code (200)
res.put_header_lines (<<["Content-Type", "text/plain"]>>)
res.set_status_code (200, Void)
res.put_header_text ("Content-Type: text/plain%R%N")
res.put_string ("Hello World!%N")
end
port_number: INTEGER = 8123
note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2012, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software

View File

@@ -1,5 +1,5 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, Eiffel Software and others"
copyright: "2011-${YEAR}, 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

@@ -20,7 +20,7 @@ feature -- Access
end
note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -79,7 +79,7 @@ feature -- Extra names
orig_path_info: STRING = "ORIG_PATH_INFO"
note
copyright: "2011-2012, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -77,8 +77,7 @@ feature -- Access: Input
input: WGI_INPUT_STREAM
-- Server input channel
require
is_not_chunked_input: not is_chunked_input
--| Could also be Chunked input, but this is transparent
deferred
end
@@ -87,13 +86,6 @@ feature -- Access: Input
deferred
end
chunked_input: detachable WGI_CHUNKED_INPUT_STREAM
-- Chunked server input channel
require
is_chunked_input: is_chunked_input
deferred
end
feature -- Access: CGI meta variables
meta_variable (a_name: READABLE_STRING_8): detachable READABLE_STRING_8
@@ -626,7 +618,7 @@ invariant
path_info_identical: path_info ~ meta_string_variable ({WGI_META_NAMES}.path_info)
note
copyright: "2011-2012, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -42,14 +42,6 @@ feature -- Status report
deferred
end
feature {WGI_RESPONSE} -- Core output operation
write (s: READABLE_STRING_8)
-- Send the string `s'
-- this can be used for header and body
deferred
end
feature -- Status setting
status_is_set: BOOLEAN
@@ -57,15 +49,17 @@ feature -- Status setting
deferred
end
set_status_code (a_code: INTEGER)
-- Set response status code
set_status_code (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8)
-- Set response status code with custom `a_reason_phrase' if precised
-- Should be done before sending any data back to the client
require
a_code_positive: a_code > 0
status_not_set: not status_committed
header_not_committed: not header_committed
deferred
ensure
status_code_set: status_code = a_code
status_reason_phrase_set: status_reason_phrase = a_reason_phrase
status_set: status_is_set
end
@@ -74,6 +68,13 @@ feature -- Status setting
deferred
end
status_reason_phrase: detachable READABLE_STRING_8
-- Custom status reason phrase for the Response (optional)
deferred
ensure
Result /= Void implies status_is_set
end
feature -- Header output operation
put_header_text (a_text: READABLE_STRING_8)
@@ -81,29 +82,27 @@ feature -- Header output operation
-- It should not contain the ending CR LF CR LF
-- since it is the duty of `put_header_text' to write it.
require
a_text_has_single_ending_crlf: a_text.count > 2 implies not a_text.substring (a_text.count - 2, a_text.count).same_string ("%R%N")
a_text_does_not_has_ending_crlf_crlf: a_text.count > 4 implies not a_text.substring (a_text.count - 4, a_text.count).same_string ("%R%N%R%N")
status_set: status_is_set
header_not_committed: not header_committed
deferred
ensure
status_set: status_is_set
header_committed: header_committed
message_writable: message_writable
end
put_header_lines (a_lines: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
require
status_set: status_is_set
header_not_committed: not header_committed
deferred
ensure
status_set: status_is_set
status_committed: status_committed
header_committed: header_committed
message_writable: message_writable
end
feature -- Output operation
put_character (c: CHARACTER_8)
-- Send the character `c'
require
message_writable: message_writable
deferred
end
put_string (s: READABLE_STRING_8)
-- Send the string `s'
require
@@ -123,8 +122,16 @@ feature -- Output operation
deferred
end
feature -- Error reporting
put_error (a_message: READABLE_STRING_8)
-- Report error described by `a_message'
-- This might be used by the underlying connector
deferred
end
note
copyright: "2011-2012, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -26,7 +26,7 @@ feature {WGI_CONNECTOR} -- Execution
end
note
copyright: "2011-2012, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -1,15 +1,298 @@
note
description: "Summary description for {WGI_CHUNKED_INPUT_STREAM}."
author: ""
date: "$Date$"
revision: "$Revision$"
deferred
class
WGI_CHUNKED_INPUT_STREAM
note
copyright: "2011-2012, Eiffel Software and others"
inherit
WGI_INPUT_STREAM
create
make
feature {NONE} -- Implementation
make (an_input: like input)
do
create last_string.make_empty
create last_chunk.make_empty
last_chunk_size := 0
index := 0
chunk_lower := 0
chunk_upper := 0
create tmp_hex_chunk_size.make_empty
input := an_input
end
feature -- Input
read_character
-- Read the next character in input stream.
-- Make the result available in `last_character'
do
index := index + 1
if index > chunk_upper then
read_chunk
if last_chunk = Void then
read_trailer
end
end
last_character := last_chunk.item (index)
end
read_string (nb: INTEGER)
-- Read the next `nb' characters and
-- make the string result available in `last_string'
local
i: like index
do
last_string.wipe_out
if last_chunk_size = 0 then
read_chunk
end
from
index := index + 1
i := index
until
i - index + 1 = nb or last_chunk_size = 0
loop
if i + nb - 1 <= chunk_upper then
last_string.append (last_chunk.substring (i, i + nb - 1))
i := i + nb - 1
else
-- Need to read new chunk
-- first get all available data from current chunk
if i <= chunk_upper then
last_string.append (last_chunk.substring (i, chunk_upper))
i := chunk_upper
end
-- then continue
read_chunk
end
end
if last_chunk_size = 0 then
read_trailer
end
index := i
end
feature -- Access
last_string: STRING_8
-- Last string read.
--
-- Note: this query *might* return the same object.
-- Therefore a clone should be used if the result
-- is to be kept beyond the next call to this feature.
-- However `last_string' is not shared between file objects.)
last_character: CHARACTER_8
-- Last item read.
feature -- Status report
is_open_read: BOOLEAN
-- Can items be read from input stream?
do
Result := input.is_open_read
end
end_of_input: BOOLEAN
-- Has the end of input stream been reached?
do
Result := input.end_of_input
end
--feature -- Input
-- data: STRING_8
-- local
-- d: like internal_data
-- do
-- d := internal_data
-- if d = Void then
-- d := fetched_data
-- internal_data := d
-- end
-- Result := d
-- end
feature {NONE} -- Parser
index, chunk_lower, chunk_upper: INTEGER
last_chunk_size: INTEGER
last_chunk: STRING_8
-- internal_data: detachable STRING_8
tmp_hex_chunk_size: STRING_8
-- fetched_data: STRING_8
-- -- Read all the data in a chunked stream.
-- -- Make the result available in `last_chunked'.
-- -- Chunked-Body = *chunk
-- -- last-chunk
-- -- trailer
-- -- CRLF
-- -- chunk = chunk-size [ chunk-extension ] CRLF
-- -- chunk-data CRLF
-- -- chunk-size = 1*HEX
-- -- last-chunk = 1*("0") [ chunk-extension ] CRLF
-- -- chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
-- -- chunk-ext-name = token
-- -- chunk-ext-val = token | quoted-string
-- -- chunk-data = chunk-size(OCTET)
-- -- trailer = *(entity-header CRLF)
-- local
-- eoc: BOOLEAN
-- s: STRING_8
-- do
-- from
-- create s.make (1024)
-- until
-- eoc
-- loop
-- read_chunk
-- if attached last_chunk as l_last_chunk then
-- s.append (l_last_chunk)
-- else
-- eoc := True
-- end
-- if last_chunk_size = 0 then
-- eoc := True
-- end
-- end
-- read_trailer
-- Result := s
-- end
read_chunk
do
chunk_lower := chunk_upper + 1
last_chunk.wipe_out
last_chunk_size := 0
read_chunk_size
if last_chunk_size > 0 then
chunk_upper := chunk_upper + last_chunk_size
read_chunk_data
end
ensure
attached last_chunk as l_last_chunk implies l_last_chunk.count = chunk_upper - chunk_lower
end
read_chunk_data
require
last_chunk.is_empty
last_chunk_size > 0
local
l_input: like input
do
l_input := input
l_input.read_string (last_chunk_size)
last_chunk := l_input.last_string
ensure
last_chunk_attached: attached last_chunk as el_last_chunk
last_chunk_size_ok: el_last_chunk.count = last_chunk_size
end
read_chunk_size
require
tmp_hex_chunk_size_is_empty: tmp_hex_chunk_size.is_empty
local
eol : BOOLEAN
c: CHARACTER
hex : HEXADECIMAL_STRING_TO_INTEGER_CONVERTER
l_input: like input
do
l_input := input
from
l_input.read_character
until
eol
loop
c := l_input.last_character
inspect c
when '%R' then
-- We are in the end of the line, we need to read the next character to start the next line.
eol := True
l_input.read_character
when ';' then
-- We are in an extension chunk data
read_extension_chunk
else
tmp_hex_chunk_size.append_character (c)
l_input.read_character
end
end
if tmp_hex_chunk_size.same_string ("0") then
last_chunk_size := 0
else
create hex.make
hex.parse_string_with_type (tmp_hex_chunk_size, hex.type_integer)
if hex.parse_successful then
last_chunk_size := hex.parsed_integer
else
last_chunk_size := 0 -- ERROR ...
end
end
tmp_hex_chunk_size.wipe_out
end
read_extension_chunk
local
l_input: like input
do
l_input := input
debug
print (" Reading extension chunk ")
end
from
l_input.read_character
until
l_input.last_character = '%R'
loop
debug
print (l_input.last_character)
end
l_input.read_character
end
end
read_trailer
local
l_input: like input
do
l_input := input
if not l_input.end_of_input then
debug
print (" Reading trailer ")
end
from
l_input.read_character
until
l_input.last_character = '%R'
loop
debug
print (l_input.last_character)
end
l_input.read_character
end
-- read the LF
l_input.read_character
end
end
feature {NONE} -- Implementation
input: WGI_INPUT_STREAM
-- Input Stream
;note
copyright: "2011-2012, 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

@@ -0,0 +1,32 @@
note
description : "[
Objects that represents the error stream
]"
specification: "EWSGI/connector specification https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/EWSGI-specification"
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
deferred class
WGI_ERROR_STREAM
feature -- Output
put_error (a_message: READABLE_STRING_8)
-- Report error described by `a_message'
-- This might be used by the underlying connector
deferred
end
note
copyright: "2011-2012, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -2,6 +2,7 @@ note
description : "[
Objects that represents the input stream
]"
specification: "EWSGI/connector specification https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/EWSGI-specification"
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
@@ -10,25 +11,154 @@ note
deferred class
WGI_INPUT_STREAM
feature -- Input
read_character
-- Read the next character in input stream.
-- Make the result available in `last_character'
require
is_open_read: is_open_read
not_end_of_input: not end_of_input
deferred
end
read_string (nb: INTEGER)
-- Read the next `nb' characters and
-- make the string result available in `last_string'
require
is_open_read: is_open_read
not_end_of_input: not end_of_input
nb_large_enough: nb > 0
deferred
ensure
last_string_count_small_enough: not end_of_input implies last_string.count <= nb
character_read: not end_of_input implies last_string.count > 0
end
read_to_string (a_string: STRING; pos, nb: INTEGER): INTEGER
-- Fill `a_string', starting at position `pos', with
-- at most `nb' characters read from input stream.
-- Return the number of characters actually read.
-- (Note that even if at least `nb' characters are available
-- in the input stream, there is no guarantee that they
-- will all be read.)
require
is_open_read: is_open_read
not_end_of_input: not end_of_input
a_string_not_void: a_string /= Void
valid_position: a_string.valid_index (pos)
nb_large_enough: nb > 0
nb_small_enough: nb <= a_string.count - pos + 1
local
i, end_pos: INTEGER
do
end_pos := pos + nb - 1
from
i := pos
until
i > end_pos
loop
read_character
if not end_of_input then
a_string.put (last_character, i)
i := i + 1
else
Result := i - pos - nb
-- Jump out of the loop.
i := end_pos + 1
end
end
Result := Result + i - pos
ensure
nb_char_read_large_enough: Result >= 0
nb_char_read_small_enough: Result <= nb
character_read: not end_of_input implies Result > 0
end
append_to_string (a_string: STRING; nb: INTEGER)
-- Append at most `nb' characters read from input stream
-- to `a_string'
-- Set `last_appended_count' to the number of characters actually read.
-- (Note that even if at least `nb' characters are available
-- in the input stream, there is no guarantee that they
-- will all be read.)
require
is_open_read: is_open_read
not_end_of_input: not end_of_input
a_string_not_void: a_string /= Void
nb_large_enough: nb > 0
local
i, end_pos: INTEGER
l_count: INTEGER
do
from
i := a_string.count + 1
end_pos := i + nb - 1
a_string.grow (end_pos)
until
i > end_pos
loop
read_character
if not end_of_input then
a_string.extend (last_character)
i := i + 1
else
l_count := i - nb
-- Jump out of the loop.
i := end_pos + 1
end
end
last_appended_count := l_count + i
ensure
nb_char_read_large_enough: last_appended_count >= 0
nb_char_read_small_enough: last_appended_count <= nb
character_read: not end_of_input implies last_appended_count > 0
end
feature -- Access
last_string: STRING_8
-- Last read string from stream
-- Last string read.
--
-- Note: this query *might* return the same object.
-- Therefore a clone should be used if the result
-- is to be kept beyond the next call to this feature.
-- However `last_string' is not shared between file objects.)
require
is_open_read: is_open_read
not_end_of_input: not end_of_input
deferred
ensure
last_string_not_void: Result /= Void
end
last_character: CHARACTER_8
-- Last item read.
require
is_open_read: is_open_read
not_end_of_input: not end_of_input
deferred
end
feature -- Basic operation
last_appended_count: INTEGER
-- Count of characters actually read by last `append_to_string' call.
read_stream (n: INTEGER)
require
n_positive: n > 0
feature -- Status report
is_open_read: BOOLEAN
-- Can items be read from input stream?
deferred
end
end_of_input: BOOLEAN
-- Has the end of input stream been reached?
require
is_open_read: is_open_read
deferred
ensure
at_max_n: last_string.count <= n
end
note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -2,6 +2,7 @@ note
description : "[
Objects that represents the output stream
]"
specification: "EWSGI/connector specification https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/EWSGI-specification"
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
@@ -10,48 +11,89 @@ note
deferred class
WGI_OUTPUT_STREAM
feature -- Core operation
feature -- Output
put_string (s: STRING_8)
-- Write `s' into the output stream
put_string (a_string: READABLE_STRING_8)
-- Write `a_string' to output stream.
require
s_not_empty: s /= Void and then not s.is_empty
is_open_write: is_open_write
a_string_not_void: a_string /= Void
deferred
end
flush
-- Flush the output stream
put_substring (a_string: READABLE_STRING_8; s, e: INTEGER)
-- Write substring of `a_string' between indexes
-- `s' and `e' to output stream.
--| Could be redefined for optimization
require
is_open_write: is_open_write
a_string_not_void: a_string /= Void
s_large_enough: s >= 1
e_small_enough: e <= a_string.count
valid_interval: s <= e + 1
do
if s <= e then
put_string (a_string.substring (s, e))
end
end
put_character (c: CHARACTER_8)
-- Write `c' to output stream.
--| Could be redefined for optimization
require
is_open_write: is_open_write
deferred
end
feature -- Specific output
put_header_line (s: READABLE_STRING_8)
-- Send `s' to http client as header line
do
put_string (s)
put_crlf
end
put_crlf
-- Send "%R%N" string
do
put_string (crlf)
end
feature -- Status writing
put_status_line (a_code: INTEGER)
put_status_line (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8)
-- Put status code line for `a_code'
-- with custom `a_reason_phrase' if precised
--| Note this is a default implementation, and could be redefined
--| for instance in relation to NPH CGI script
require
a_code_positive: a_code > 0
deferred
end
feature -- Basic operation
feature -- Status report
put_substring (s: STRING; start_index, end_index: INTEGER)
-- Write `s[start_index:end_index]' into the output stream
is_open_write: BOOLEAN
-- Can items be written to output stream?
deferred
end
feature -- Basic operations
flush
-- Flush buffered data to disk.
require
s_not_empty: s /= Void and then not s.is_empty
do
put_string (s.substring (start_index, end_index))
is_open_write: is_open_write
deferred
end
put_header_line (s: STRING)
-- Send `s' to http client as header line
do
put_string (s)
put_string ("%R%N")
end
feature -- Constant
crlf: STRING = "%R%N"
note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -1,36 +0,0 @@
note
description: "Summary description for {WGI_SERVICE}."
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
deferred class
WGI_SERVICE
feature {NONE} -- Execution
execute (req: WGI_REQUEST; res: WGI_RESPONSE)
-- Execute the request
-- See `req.input' for input stream
-- `req.environment' for the Gateway environment
-- and `res' for the output buffer
require
res_status_unset: not res.status_is_set
deferred
ensure
res_status_set: res.status_is_set
res_committed: res.message_committed
end
note
copyright: "2011-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -27,9 +27,18 @@ feature {NONE} -- Initialization
input := a_input
set_meta_variables (a_vars)
update_path_info
if attached http_transfer_encoding as l_transfer_encoding and then l_transfer_encoding.same_string ("chunked") then
update_input
end
update_input
-- Update input, depending on Transfer-Encoding value.
do
if
attached http_transfer_encoding as l_transfer_encoding and then
l_transfer_encoding.same_string (once "chunked")
then
is_chunked_input := True
create chunked_input.make (a_input)
create {WGI_CHUNKED_INPUT_STREAM} input.make (input)
end
end
@@ -40,9 +49,7 @@ feature -- Access: Input
input: WGI_INPUT_STREAM
-- Server input channel
chunked_input: detachable WGI_CHUNKED_INPUT_STREAM
-- Chunked server input channel
--| Could be a chunked input as well
feature -- EWSGI access
@@ -244,8 +251,10 @@ feature {NONE} -- Element change: CGI meta parameter related to PATH_INFO
table: HASH_TABLE [READABLE_STRING_8, READABLE_STRING_8]
l_query_string: like query_string
l_request_uri: detachable STRING_32
l_empty_string: like empty_string
do
create {STRING_8} empty_string.make_empty
create {STRING_8} l_empty_string.make_empty
empty_string := l_empty_string
create table.make (a_vars.count)
table.compare_objects
@@ -260,11 +269,11 @@ feature {NONE} -- Element change: CGI meta parameter related to PATH_INFO
end
--| QUERY_STRING
l_query_string := meta_string_variable_or_default ({WGI_META_NAMES}.query_string, empty_string, False)
l_query_string := meta_string_variable_or_default ({WGI_META_NAMES}.query_string, l_empty_string, False)
query_string := l_query_string
--| REQUEST_METHOD
request_method := meta_string_variable_or_default ({WGI_META_NAMES}.request_method, empty_string, False)
request_method := meta_string_variable_or_default ({WGI_META_NAMES}.request_method, l_empty_string, False)
--| CONTENT_TYPE
s := meta_string_variable ({WGI_META_NAMES}.content_type)
@@ -278,10 +287,10 @@ feature {NONE} -- Element change: CGI meta parameter related to PATH_INFO
content_length := meta_string_variable ({WGI_META_NAMES}.content_length)
--| PATH_INFO
path_info := meta_string_variable_or_default ({WGI_META_NAMES}.path_info, empty_string, False)
path_info := meta_string_variable_or_default ({WGI_META_NAMES}.path_info, l_empty_string, False)
--| SERVER_NAME
server_name := meta_string_variable_or_default ({WGI_META_NAMES}.server_name, empty_string, False)
server_name := meta_string_variable_or_default ({WGI_META_NAMES}.server_name, l_empty_string, False)
--| SERVER_PORT
s := meta_string_variable ({WGI_META_NAMES}.server_port)
@@ -292,13 +301,13 @@ feature {NONE} -- Element change: CGI meta parameter related to PATH_INFO
end
--| SCRIPT_NAME
script_name := meta_string_variable_or_default ({WGI_META_NAMES}.script_name, empty_string, False)
script_name := meta_string_variable_or_default ({WGI_META_NAMES}.script_name, l_empty_string, False)
--| REMOTE_ADDR
remote_addr := meta_string_variable_or_default ({WGI_META_NAMES}.remote_addr, empty_string, False)
remote_addr := meta_string_variable_or_default ({WGI_META_NAMES}.remote_addr, l_empty_string, False)
--| REMOTE_HOST
remote_host := meta_string_variable_or_default ({WGI_META_NAMES}.remote_host, empty_string, False)
remote_host := meta_string_variable_or_default ({WGI_META_NAMES}.remote_host, l_empty_string, False)
--| REQUEST_URI
s := meta_string_variable ({WGI_META_NAMES}.request_uri)
@@ -358,6 +367,12 @@ feature {NONE} -- Element change: CGI meta parameter related to PATH_INFO
feature {NONE} -- Implementation: utilities
has_white_space (s: READABLE_STRING_8): BOOLEAN
-- `s' has white space?
do
Result := s.has (' ') or else s.has ('%T')
end
single_slash_starting_string (s: READABLE_STRING_8): STRING_8
-- Return the string `s' (or twin) with one and only one starting slash
local
@@ -411,7 +426,7 @@ invariant
empty_string_unchanged: empty_string.is_empty
note
copyright: "2011-2012, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -17,9 +17,10 @@ create
feature {NONE} -- Initialization
make (a_output: like output)
make (a_output: like output; a_error: like error)
do
output := a_output
error := a_error
end
feature {WGI_CONNECTOR, WGI_SERVICE} -- Commit
@@ -48,68 +49,51 @@ feature -- Status report
Result := status_is_set and header_committed
end
feature {NONE} -- Core output operation
write (s: READABLE_STRING_8)
-- Send the content of `s'
-- this can be used for header and body
do
output.put_string (s)
end
feature -- Status setting
status_is_set: BOOLEAN
-- Is status set?
do
Result := status_code /= 0
Result := status_code > 0
end
set_status_code (a_code: INTEGER)
set_status_code (a_code: INTEGER; a_reason_phrase: detachable READABLE_STRING_8)
-- Set response status code
-- Should be done before sending any data back to the client
do
status_code := a_code
output.put_status_line (a_code)
status_reason_phrase := a_reason_phrase
output.put_status_line (a_code, a_reason_phrase)
status_committed := True
end
status_code: INTEGER
-- Response status
status_reason_phrase: detachable READABLE_STRING_8
-- Custom status reason phrase for the Response (optional)
feature -- Header output operation
put_header_text (a_text: READABLE_STRING_8)
do
write (a_text)
write (crlf)
output.put_string (a_text)
output.put_crlf
header_committed := True
end
put_header_lines (a_lines: ITERABLE [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]])
local
h: STRING_8
do
create h.make (256)
across
a_lines as c
loop
h.append (c.item.name)
h.append_character (':')
h.append_character (' ')
h.append (c.item.value)
h.append_character ('%R')
h.append_character ('%N')
end
put_header_text (h)
end
feature -- Output operation
put_character (c: CHARACTER_8)
-- Send the character `c'
do
output.put_character (c)
end
put_string (s: READABLE_STRING_8)
-- Send the string `s'
do
write (s)
output.put_string (s)
end
put_substring (s: READABLE_STRING_8; start_index, end_index: INTEGER)
@@ -124,16 +108,27 @@ feature -- Output operation
output.flush
end
feature {NONE} -- Implementation: Access
feature -- Error reporting
crlf: STRING = "%R%N"
-- End of header
put_error (a_message: READABLE_STRING_8)
-- Report error described by `a_message'
-- This might be used by the underlying connector
do
if attached error as err then
err.put_error (a_message)
end
end
feature {NONE} -- Implementation: Access
output: WGI_OUTPUT_STREAM
-- Server output channel
error: detachable WGI_ERROR_STREAM
-- Server output channel
;note
copyright: "2011-2012, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -36,7 +36,7 @@ invariant
callback_attached: callback /= Void
note
copyright: "2011-2011, Eiffel Software and others"
copyright: "2011-2012, 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

@@ -1,210 +0,0 @@
note
description: "Summary description for {WGI_CHUNKED_INPUT_STREAM}."
author: ""
date: "$Date$"
revision: "$Revision$"
class
WGI_CHUNKED_INPUT_STREAM
create
make
feature {NONE} -- Implementation
make (an_input: like input)
do
create tmp_hex_chunk_size.make_empty
input := an_input
end
feature -- Input
data: STRING_8
local
d: like internal_data
do
d := internal_data
if d = Void then
d := fetched_data
internal_data := d
end
Result := d
end
feature {NONE} -- Parser
internal_data: detachable STRING_8
tmp_hex_chunk_size: STRING_8
last_chunk_size: INTEGER
last_chunk: detachable STRING_8
fetched_data: STRING_8
-- Read all the data in a chunked stream.
-- Make the result available in `last_chunked'.
-- Chunked-Body = *chunk
-- last-chunk
-- trailer
-- CRLF
-- chunk = chunk-size [ chunk-extension ] CRLF
-- chunk-data CRLF
-- chunk-size = 1*HEX
-- last-chunk = 1*("0") [ chunk-extension ] CRLF
-- chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
-- chunk-ext-name = token
-- chunk-ext-val = token | quoted-string
-- chunk-data = chunk-size(OCTET)
-- trailer = *(entity-header CRLF)
local
eoc: BOOLEAN
s: STRING_8
do
from
create s.make (1024)
until
eoc
loop
read_chunk
if attached last_chunk as l_last_chunk then
s.append (l_last_chunk)
else
eoc := True
end
if last_chunk_size = 0 then
eoc := True
end
end
read_trailer
Result := s
end
reset_chunk
do
last_chunk := Void
last_chunk_size := 0
end
read_chunk
do
reset_chunk
read_chunk_size
if last_chunk_size > 0 then
read_chunk_data
end
end
read_chunk_data
require
last_chunk_size > 0
do
input.read_string (last_chunk_size)
last_chunk := input.last_string
-- read CRLF
input.read_character
if input.last_character = '%R' then
input.read_character
end
ensure
last_chunk_attached: attached last_chunk as el_last_chunk
last_chunk_size_ok: el_last_chunk.count = last_chunk_size
end
read_chunk_size
require
tmp_hex_chunk_size_is_empty: tmp_hex_chunk_size.is_empty
local
eol : BOOLEAN
c: CHARACTER
hex : HEXADECIMAL_STRING_TO_INTEGER_CONVERTER
do
from
input.read_character
until
eol
loop
c := input.last_character
inspect c
when '%R' then
-- We are in the end of the line, we need to read the next character to start the next line.
eol := True
input.read_character
when ';' then
-- We are in an extension chunk data
read_extension_chunk
else
tmp_hex_chunk_size.append_character (c)
input.read_character
end
end
if tmp_hex_chunk_size.same_string ("0") then
last_chunk_size := 0
else
create hex.make
hex.parse_string_with_type (tmp_hex_chunk_size, hex.type_integer)
if hex.parse_successful then
last_chunk_size := hex.parsed_integer
else
last_chunk_size := 0 -- ERROR ...
end
end
tmp_hex_chunk_size.wipe_out
end
read_extension_chunk
do
debug
print (" Reading extension chunk ")
end
from
input.read_character
until
input.last_character = '%R'
loop
debug
print (input.last_character)
end
input.read_character
end
end
read_trailer
do
if not input.end_of_input then
debug
print (" Reading trailer ")
end
from
input.read_character
until
input.last_character = '%R'
loop
debug
print (input.last_character)
end
input.read_character
end
-- read the LF
input.read_character
end
end
feature {NONE} -- Implementation
input: WGI_INPUT_STREAM
-- Input Stream
;note
copyright: "2011-2012, 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,128 +0,0 @@
note
description : "[
Objects that represents the input stream
]"
specification: "EWSGI/connector specification https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/EWSGI-specification"
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
deferred class
WGI_INPUT_STREAM
feature -- Input
read_character
-- Read the next character in input stream.
-- Make the result available in `last_character'.
require
is_open_read: is_open_read
not_end_of_input: not end_of_input
deferred
ensure
same_last_string_reference: last_string = old last_string
end
read_string (nb: INTEGER)
require
is_open_read: is_open_read
not_end_of_input: not end_of_input
nb_large_enough: nb > 0
deferred
ensure
last_string_count_small_enough: not end_of_input implies last_string.count <= nb
character_read: not end_of_input implies last_string.count > 0
same_last_string_reference: last_string = old last_string
end
read_to_string (a_string: STRING; pos, nb: INTEGER): INTEGER
-- Fill `a_string', starting at position `pos', with
-- at most `nb' characters read from input stream.
-- Return the number of characters actually read.
-- (Note that even if at least `nb' characters are available
-- in the input stream, there is no guarantee that they
-- will all be read.)
require
is_open_read: is_open_read
not_end_of_input: not end_of_input
a_string_not_void: a_string /= Void
valid_position: a_string.valid_index (pos)
nb_large_enough: nb > 0
nb_small_enough: nb <= a_string.count - pos + 1
local
i, end_pos: INTEGER
do
end_pos := pos + nb - 1
from
i := pos
until
i > end_pos
loop
read_character
if not end_of_input then
a_string.put (last_character, i)
i := i + 1
else
Result := i - pos - nb
-- Jump out of the loop.
i := end_pos + 1
end
end
Result := Result + i - pos
ensure
nb_char_read_large_enough: Result >= 0
nb_char_read_small_enough: Result <= nb
character_read: not end_of_input implies Result > 0
same_last_string_reference: last_string = old last_string
end
feature -- Access
last_string: STRING_8
-- Last string read
-- (Note: this query always return the same object.
-- Therefore a clone should be used if the result
-- is to be kept beyond the next call to this feature.
-- However `last_string' is not shared between file objects.)
require
is_open_read: is_open_read
not_end_of_input: not end_of_input
deferred
ensure
last_string_not_void: Result /= Void
end
last_character: CHARACTER_8
-- Last item read
require
is_open_read: is_open_read
not_end_of_input: not end_of_input
deferred
end
feature -- Status report
is_open_read: BOOLEAN
-- Can items be read from input stream?
deferred
end
end_of_input: BOOLEAN
-- Has the end of input stream been reached?
require
is_open_read: is_open_read
deferred
end
note
copyright: "2011-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -1,93 +0,0 @@
note
description : "[
Objects that represents the output stream
]"
specification: "EWSGI/connector specification https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki/EWSGI-specification"
legal: "See notice at end of class."
status: "See notice at end of class."
date: "$Date$"
revision: "$Revision$"
deferred class
WGI_OUTPUT_STREAM
feature -- Output
put_string (a_string: READABLE_STRING_8)
-- Write `a_string' to output stream.
require
is_open_write: is_open_write
a_string_not_void: a_string /= Void
deferred
end
put_substring (a_string: READABLE_STRING_8; s, e: INTEGER)
-- Write substring of `a_string' between indexes
-- `s' and `e' to output stream.
--| Could be redefined for optimization
require
is_open_write: is_open_write
a_string_not_void: a_string /= Void
s_large_enough: s >= 1
e_small_enough: e <= a_string.count
valid_interval: s <= e + 1
do
if s <= e then
put_string (a_string.substring (s, e))
end
end
put_character_8 (c: CHARACTER_8)
-- Write `c' to output stream.
--| Could be redefined for optimization
require
is_open_write: is_open_write
do
put_string (c.out)
end
feature -- Specific output
put_header_line (s: READABLE_STRING_8)
-- Send `s' to http client as header line
do
put_string (s)
put_string ("%R%N")
end
feature -- Status writing
put_status_line (a_code: INTEGER)
-- Put status code line for `a_code'
--| Note this is a default implementation, and could be redefined
--| for instance in relation to NPH CGI script
deferred
end
feature -- Status report
is_open_write: BOOLEAN
-- Can items be written to output stream?
deferred
end
feature -- Basic operations
flush
-- Flush buffered data to disk.
require
is_open_write: is_open_write
deferred
end
note
copyright: "2011-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
source: "[
Eiffel Software
5949 Hollister Ave., Goleta, CA 93117 USA
Telephone 805-685-1006, Fax 805-685-6869
Website http://www.eiffel.com
Customer support http://support.eiffel.com
]"
end

View File

@@ -55,6 +55,14 @@ feature -- FCGI output
io.put_string (a_str)
end
feature -- Error
put_error (a_str: READABLE_STRING_8)
-- Put `a_str' on the FastCGI stdout.
do
io.error.put_string (a_str)
end
feature -- FCGI Input
read_from_stdin (n: INTEGER)

View File

@@ -96,6 +96,15 @@ feature -- Output
"FCGI_fwrite($v, 1, $n, FCGI_stdout);"
end
feature -- Error
put_error (v: POINTER; n: INTEGER)
external
"C inline use %"fcgi_stdio.h%""
alias
"FCGI_fwrite($v, 1, $n, FCGI_stderr);"
end
feature -- Access
stdout: POINTER
@@ -114,6 +123,14 @@ feature -- Access
"FCGI_stdin"
end
stderr: POINTER
-- FCGI_stderr() return pointer on error FCGI_FILE
external
"C inline use %"fcgi_stdio.h%""
alias
"FCGI_stderr"
end
note
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -77,6 +77,18 @@ feature -- FCGI output
{FCGI_C_API}.put_string (l_c_str.item, l_c_str.count)
end
feature -- Error
put_error (a_message: READABLE_STRING_8)
-- Put error message `a_message' on the FastCGI stderr
local
l_c_str: C_STRING
do
l_c_str := c_buffer
l_c_str.set_string (a_message)
fcgi.put_error (l_c_str.item, l_c_str.count)
end
feature -- FCGI Input
copy_from_stdin (n: INTEGER; tf: FILE)

View File

@@ -101,6 +101,15 @@ feature -- Output
i := fwrite (v, 1, n, stdout)
end
feature -- Error
put_error (v: POINTER; n: INTEGER)
local
i: INTEGER
do
i := fwrite (v, 1, n, stderr)
end
feature {NONE} -- Output
fwrite (v: POINTER; a_size: INTEGER; n: INTEGER; fp: POINTER): INTEGER
@@ -129,6 +138,15 @@ feature -- Access
"FCGI_stdin"
end
stderr: POINTER
-- FCGI_stderr() return pointer on error FCGI_FILE
external
"C inline use %"fcgi_stdio.h%""
alias
"FCGI_stderr"
end
note
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"

View File

@@ -136,6 +136,18 @@ feature -- FCGI output
fcgi.put_string (l_c_str.item, l_c_str.count)
end
feature -- Error
put_error (a_message: READABLE_STRING_8)
-- Put error message `a_message' on the FastCGI stderr
local
l_c_str: C_STRING
do
l_c_str := c_buffer
l_c_str.set_string (a_message)
fcgi.put_error (l_c_str.item, l_c_str.count)
end
feature -- FCGI input
copy_from_stdin (n: INTEGER; f: FILE)

View File

@@ -1,5 +1,5 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, Eiffel Software and others"
copyright: "2011-${YEAR}, 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

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="wsf_all" uuid="223E2E7D-AA90-4ADC-93CB-D304E794E3E6" library_target="wsf_all">
<target name="wsf_all">
<root all_classes="true"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/\.git$</exclude>
<exclude>/\.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<library name="ewsgi" location="../../ewsgi/ewsgi-safe.ecf"/>
<library name="wsf" location="../wsf-safe.ecf"/>
<library name="connector_cgi" location="../../ewsgi/connectors/cgi/cgi-safe.ecf"/>
<library name="connector_libfcgi" location="../../ewsgi/connectors/libfcgi/libfcgi-safe.ecf"/>
<library name="connector_nino" location="../../ewsgi/connectors/nino/nino-safe.ecf"/>
<library name="nino" location="..\..\..\..\contrib\library\server\nino\nino-safe.ecf" readonly="false">
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
</library>
<library name="error" location="..\..\..\error\error-safe.ecf"/>
<library name="http" location="..\..\..\protocol\http\http-safe.ecf"/>
<library name="encoder" location="..\..\..\text\encoder\encoder-safe.ecf" readonly="false"/>
<cluster name="wsf_nino" location="./nino" recursive="true"/>
<cluster name="wsf_cgi" location="./cgi" recursive="true"/>
<cluster name="wsf_libfcgi" location="./libfcgi" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="wsf_cgi" uuid="1B416A7F-D49B-43FC-8308-F14AA9531AF8" library_target="wsf_cgi">
<target name="wsf_cgi">
<root all_classes="true"/>
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/\.git$</exclude>
<exclude>/\.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<library name="ewsgi" location="../../ewsgi/ewsgi-safe.ecf"/>
<library name="wsf" location="../wsf-safe.ecf"/>
<library name="connector_cgi" location="../../ewsgi/connectors/cgi/cgi-safe.ecf"/>
<library name="error" location="..\..\..\error\error-safe.ecf"/>
<library name="http" location="..\..\..\protocol\http\http-safe.ecf"/>
<library name="encoder" location="..\..\..\text\encoder\encoder-safe.ecf" readonly="false"/>
<cluster name="wsf_cgi" location="./cgi" recursive="true"/>
</target>
</system>

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