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:
Jocelyn Fiat
2011-08-01 16:41:16 +02:00
parent bbcc9ef44b
commit 4eb22d0272
61 changed files with 1570 additions and 534 deletions

View 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

View 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

View File

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

View File

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

View File

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