Tried to reduce gap between both EWSGI proposals
Re-adapt the Spec-compliant solution (instead of Lib-compliant solution). Thus no more 100% deferred interface. Rename EWSGI_RESPONSE into EWSGI_RESPONSE_BUFFER Added in extra/response-as-result/ an copy/paste from the implementation of Paul's proposal (not up to date with Paul's spec). But this is mainly for information and tests. Removed part of the ewsgi/specification interfaces ... to be able to test EWSGI compliant library against the pure specification (experimental). Renamed most of the GW_... into EWSGI_...
This commit is contained in:
105
library/server/ewsgi/src/extra/gw_buffered_response.e
Normal file
105
library/server/ewsgi/src/extra/gw_buffered_response.e
Normal file
@@ -0,0 +1,105 @@
|
||||
note
|
||||
description: "Summary description for {GW_BUFFERED_RESPONSE}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_BUFFERED_RESPONSE
|
||||
|
||||
inherit
|
||||
EWSGI_RESPONSE_BUFFER
|
||||
rename
|
||||
make as buffer_make
|
||||
redefine
|
||||
write,
|
||||
flush,
|
||||
commit
|
||||
end
|
||||
|
||||
create {EWSGI_APPLICATION}
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_output: like output; a_buffer_size: INTEGER)
|
||||
do
|
||||
buffer_make (a_output)
|
||||
buffer_capacity := a_buffer_size
|
||||
create buffer.make (a_buffer_size)
|
||||
end
|
||||
|
||||
buffer: STRING_8
|
||||
|
||||
buffer_capacity: INTEGER
|
||||
|
||||
buffer_count: INTEGER
|
||||
|
||||
feature {NONE} -- Core output operation
|
||||
|
||||
write (s: STRING)
|
||||
-- Send the content of `s'
|
||||
local
|
||||
buf: like buffer
|
||||
len_b, len_s: INTEGER
|
||||
do
|
||||
buf := buffer
|
||||
len_s := s.count
|
||||
len_b := buffer_count
|
||||
if len_b + len_s >= buffer_capacity then
|
||||
flush_buffer
|
||||
if len_s >= buffer_capacity then
|
||||
-- replace buffer by `s'
|
||||
buffer := s
|
||||
buffer_count := len_s
|
||||
flush_buffer
|
||||
-- restore buffer with `buf'
|
||||
buffer := buf
|
||||
else
|
||||
buf.append (s)
|
||||
buffer_count := len_s
|
||||
end
|
||||
else
|
||||
buf.append (s)
|
||||
buffer_count := len_b + len_s
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Output operation
|
||||
|
||||
flush
|
||||
do
|
||||
flush_buffer
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
flush_buffer
|
||||
require
|
||||
buffer_count_match_buffer: buffer_count = buffer.count
|
||||
do
|
||||
output.put_string (buffer)
|
||||
buffer_count := 0
|
||||
ensure
|
||||
buffer_flushed: buffer_count = 0 and buffer.count = 0
|
||||
end
|
||||
|
||||
feature {EWSGI_APPLICATION} -- Commit
|
||||
|
||||
commit
|
||||
do
|
||||
flush_buffer
|
||||
Precursor
|
||||
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
|
||||
109
library/server/ewsgi/src/extra/in_memory/gw_in_memory_response.e
Normal file
109
library/server/ewsgi/src/extra/in_memory/gw_in_memory_response.e
Normal file
@@ -0,0 +1,109 @@
|
||||
note
|
||||
description: "Summary description for {GW_IN_MEMORY_RESPONSE}."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
GW_IN_MEMORY_RESPONSE
|
||||
|
||||
inherit
|
||||
EWSGI_RESPONSE_BUFFER
|
||||
redefine
|
||||
make,
|
||||
commit,
|
||||
write,
|
||||
set_status_code,
|
||||
write_header,
|
||||
flush
|
||||
end
|
||||
|
||||
create {EWSGI_APPLICATION}
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_output: EWSGI_OUTPUT_STREAM)
|
||||
do
|
||||
Precursor (a_output)
|
||||
create header.make
|
||||
create body.make (100)
|
||||
end
|
||||
|
||||
header: GW_HEADER
|
||||
|
||||
body: STRING_8
|
||||
|
||||
feature {NONE} -- Status output
|
||||
|
||||
write (s: STRING)
|
||||
-- Send the content of `s'
|
||||
do
|
||||
body.append (s)
|
||||
end
|
||||
|
||||
feature -- Status setting
|
||||
|
||||
set_status_code (a_code: INTEGER)
|
||||
-- Set response status code
|
||||
-- Should be done before sending any data back to the client
|
||||
do
|
||||
status_code := a_code
|
||||
end
|
||||
|
||||
feature -- Output operation
|
||||
|
||||
flush
|
||||
do
|
||||
--| Do nothing ... this is in_memory response
|
||||
end
|
||||
|
||||
feature -- Header output operation
|
||||
|
||||
write_header (a_status_code: INTEGER; a_headers: detachable ARRAY [TUPLE [key: STRING; value: STRING]])
|
||||
-- Send headers with status `a_status', and headers from `a_headers'
|
||||
local
|
||||
h: GW_HEADER
|
||||
i,n: INTEGER
|
||||
do
|
||||
set_status_code (a_status_code)
|
||||
create h.make
|
||||
if a_headers /= Void then
|
||||
from
|
||||
i := a_headers.lower
|
||||
n := a_headers.upper
|
||||
until
|
||||
i > n
|
||||
loop
|
||||
h.put_header_key_value (a_headers[i].key, a_headers[i].value)
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
header := h
|
||||
end
|
||||
|
||||
feature {EWSGI_APPLICATION} -- Commit
|
||||
|
||||
commit
|
||||
local
|
||||
o: like output
|
||||
do
|
||||
o := output
|
||||
o.put_status_line (status_code)
|
||||
o.put_string (header.string)
|
||||
header_committed := True
|
||||
o.put_string (body)
|
||||
o.flush
|
||||
Precursor
|
||||
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
|
||||
@@ -0,0 +1,33 @@
|
||||
note
|
||||
description: "Summary description for {GW_IN_MEMORY_RESPONSE_APPLICATION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
GW_IN_MEMORY_RESPONSE_APPLICATION
|
||||
|
||||
inherit
|
||||
EWSGI_APPLICATION
|
||||
redefine
|
||||
new_response
|
||||
end
|
||||
|
||||
feature -- Factory
|
||||
|
||||
new_response (req: EWSGI_REQUEST; a_output: EWSGI_OUTPUT_STREAM): GW_IN_MEMORY_RESPONSE
|
||||
do
|
||||
create {GW_IN_MEMORY_RESPONSE} Result.make (a_output)
|
||||
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
|
||||
@@ -0,0 +1,225 @@
|
||||
note
|
||||
description: "[
|
||||
An EWSGI response. This may be used as is or specialized (subclassed)
|
||||
if a developer wishes to reimplement their own version of the feature
|
||||
'read_message_body_block' for supporting a block-based message body
|
||||
response.
|
||||
]"
|
||||
author: "Paul Cohen <paul.cohen@seibostudio.se>"
|
||||
status: "Draft"
|
||||
|
||||
class EWSGI_RESPONSE
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Create new response object
|
||||
do
|
||||
is_buffered := False
|
||||
ready_to_transmit := False
|
||||
end_of_blocks := False
|
||||
max_block_size := default_max_block_size
|
||||
current_block := ""
|
||||
create headers_table.make (10)
|
||||
end
|
||||
|
||||
feature {EWSGI_RESPONSE_APPLICATION} -- Response status
|
||||
|
||||
transmit_to (res: EWSGI_RESPONSE_BUFFER)
|
||||
do
|
||||
res.set_status_code (status)
|
||||
res.write_string (headers)
|
||||
from
|
||||
read_block
|
||||
res.write_string (last_block)
|
||||
-- res.flush
|
||||
until
|
||||
end_of_blocks
|
||||
loop
|
||||
read_block
|
||||
res.write_string (last_block)
|
||||
-- res.flush
|
||||
end
|
||||
end
|
||||
|
||||
ready_to_transmit: BOOLEAN
|
||||
-- Is this response ready to be transmitted?
|
||||
|
||||
set_ready_to_transmit
|
||||
-- Set response to ready to transmit.
|
||||
do
|
||||
if is_buffered then
|
||||
set_header ("Content-Length", current_block.count.out)
|
||||
-- elseif tmp_file /= Void then
|
||||
-- if tmp_file.is_open_write then
|
||||
-- tmp_file.close
|
||||
-- set_header ("Content-Length", tmp_file.count.out)
|
||||
-- end
|
||||
end
|
||||
ready_to_transmit := True
|
||||
ensure
|
||||
ready_to_transmit
|
||||
end
|
||||
|
||||
feature {EWSGI_RESPONSE_APPLICATION} -- Message start line and status
|
||||
|
||||
status: INTEGER
|
||||
-- HTTP status code
|
||||
|
||||
set_status (s: INTEGER)
|
||||
-- Set 'status_code'.
|
||||
do
|
||||
status := s
|
||||
set_header ("Status", s.out)
|
||||
ensure
|
||||
status = s
|
||||
end
|
||||
|
||||
start_line: STRING
|
||||
-- HTTP message start-line
|
||||
do
|
||||
if attached status as st then
|
||||
Result := "HTTP/1.1 " + st.out + " " + status_text (st) + crlf
|
||||
else
|
||||
Result := "HTTP/1.1 200 " + status_text (200) + crlf
|
||||
end
|
||||
end
|
||||
|
||||
feature {EWSGI_RESPONSE_APPLICATION} -- Message headers
|
||||
|
||||
headers: STRING
|
||||
-- HTTP message headers including trailing empty line.
|
||||
local
|
||||
t: HASH_TABLE [STRING, STRING]
|
||||
do
|
||||
Result := ""
|
||||
t := headers_table
|
||||
from
|
||||
t.start
|
||||
until
|
||||
t.after
|
||||
loop
|
||||
Result.append (t.key_for_iteration + ": " + t.item_for_iteration + crlf)
|
||||
t.forth
|
||||
end
|
||||
Result.append (crlf)
|
||||
end
|
||||
|
||||
headers_table: HASH_TABLE [STRING, STRING]
|
||||
-- Hash table of HTTP headers
|
||||
|
||||
set_header (key, value: STRING)
|
||||
-- Set the HTTP header with the given 'key' to the given 'value'.
|
||||
do
|
||||
headers_table.put (value, key)
|
||||
ensure
|
||||
headers_table.has (key) and headers_table @ key = value
|
||||
end
|
||||
|
||||
feature {EWSGI_RESPONSE_APPLICATION} -- Message body
|
||||
|
||||
read_block
|
||||
-- Read a message body block.
|
||||
do
|
||||
if is_buffered then
|
||||
end_of_blocks := True
|
||||
-- else
|
||||
-- -- File based block-based output
|
||||
-- -- TBD!
|
||||
end
|
||||
ensure
|
||||
not is_buffered implies last_block.count <= max_block_size
|
||||
end
|
||||
|
||||
last_block: STRING
|
||||
-- Last message body block that has been read.
|
||||
do
|
||||
Result := current_block
|
||||
end
|
||||
|
||||
is_buffered: BOOLEAN
|
||||
-- Is the entire entity body buffered in memory (STRING)?
|
||||
|
||||
end_of_blocks: BOOLEAN
|
||||
-- Has the last of the entity body blocks been read?
|
||||
|
||||
set_message_body (s: STRING)
|
||||
-- Set the message body to 's'. Use this for when you want a memory
|
||||
-- buffered response.
|
||||
do
|
||||
current_block := s
|
||||
is_buffered := True
|
||||
set_ready_to_transmit
|
||||
ensure
|
||||
is_buffered
|
||||
ready_to_transmit
|
||||
last_block.is_equal (s)
|
||||
end
|
||||
|
||||
max_block_size: INTEGER
|
||||
-- Maximum block size returned by message body if not buffered
|
||||
|
||||
set_max_block_size (block_size: INTEGER)
|
||||
-- Set 'max_block_size'.
|
||||
do
|
||||
max_block_size := block_size
|
||||
ensure
|
||||
max_block_size = block_size
|
||||
end
|
||||
|
||||
-- write_message_block (s: STRING)
|
||||
-- -- Write message body block 's' to a temporary file. Us this when
|
||||
-- -- you want a non-buffered response.
|
||||
-- require
|
||||
-- not is_buffered
|
||||
-- do
|
||||
-- -- TBD!
|
||||
-- ensure
|
||||
-- not is_buffered
|
||||
-- not ready_to_transmit
|
||||
-- end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
-- tmp_file_name: STRING
|
||||
|
||||
-- tmp_file: detachable FILE
|
||||
-- -- Created with mktmp
|
||||
|
||||
-- position: INTEGER
|
||||
-- -- Current read position in tmp_file
|
||||
|
||||
current_block: STRING
|
||||
-- Current message body block
|
||||
|
||||
default_max_block_size: INTEGER = 65536
|
||||
-- Default value of 'max_block_size'
|
||||
|
||||
crlf: STRING = "%/13/%/10/"
|
||||
|
||||
status_text (code: INTEGER): STRING
|
||||
do
|
||||
inspect code
|
||||
when 500 then
|
||||
Result := "Internal Server Error"
|
||||
when 200 then
|
||||
Result := "OK"
|
||||
else
|
||||
Result := "Code " + code.out
|
||||
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
|
||||
@@ -0,0 +1,57 @@
|
||||
note
|
||||
description: "Summary description for {EWSGI_RESPONSE_APPLICATION} "
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
EWSGI_RESPONSE_APPLICATION
|
||||
|
||||
feature -- Execution
|
||||
|
||||
execute (req: EWSGI_REQUEST; res: EWSGI_RESPONSE_BUFFER)
|
||||
-- Execute the request
|
||||
-- See `req.input' for input stream
|
||||
-- `req.environment' for the Gateway environment
|
||||
-- and `res.output' for output stream
|
||||
local
|
||||
rs: EWSGI_RESPONSE
|
||||
s: STRING
|
||||
do
|
||||
rs := response (req)
|
||||
if rs.ready_to_transmit then
|
||||
rs.transmit_to (res)
|
||||
else
|
||||
-- Report internal server error.
|
||||
-- Response not ready to transmit!
|
||||
-- Implementor of EWSGI_APPLICATION has not done his job!
|
||||
create rs.make
|
||||
rs.set_status (500)
|
||||
rs.set_header ("Content-Type", "text/plain")
|
||||
rs.set_message_body ("Incomplete server implementation: Response not ready to transmit.%NTell the programmer to finish his/her job!")
|
||||
rs.transmit_to (res)
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Response
|
||||
|
||||
response (request: EWSGI_REQUEST): EWSGI_RESPONSE
|
||||
-- HTTP response for given 'request'.
|
||||
deferred
|
||||
ensure
|
||||
ready_to_transmit: Result.ready_to_transmit
|
||||
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
|
||||
Reference in New Issue
Block a user