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.
This commit is contained in:
Jocelyn Fiat
2012-04-13 16:33:49 +02:00
parent e6a727ee42
commit 0bd2d16c12
5 changed files with 171 additions and 112 deletions

View File

@@ -77,8 +77,7 @@ feature -- Access: Input
input: WGI_INPUT_STREAM input: WGI_INPUT_STREAM
-- Server input channel -- Server input channel
require --| Could also be Chunked input, but this is transparent
is_not_chunked_input: not is_chunked_input
deferred deferred
end end
@@ -87,13 +86,6 @@ feature -- Access: Input
deferred deferred
end 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 feature -- Access: CGI meta variables
meta_variable (a_name: READABLE_STRING_8): detachable READABLE_STRING_8 meta_variable (a_name: READABLE_STRING_8): detachable READABLE_STRING_8

View File

@@ -1,12 +1,14 @@
note note
description: "Summary description for {WGI_CHUNKED_INPUT_STREAM}." description: "Summary description for {WGI_CHUNKED_INPUT_STREAM}."
author: ""
date: "$Date$" date: "$Date$"
revision: "$Revision$" revision: "$Revision$"
class class
WGI_CHUNKED_INPUT_STREAM WGI_CHUNKED_INPUT_STREAM
inherit
WGI_INPUT_STREAM
create create
make make
@@ -14,90 +16,177 @@ feature {NONE} -- Implementation
make (an_input: like input) make (an_input: like input)
do 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 create tmp_hex_chunk_size.make_empty
input := an_input input := an_input
end end
feature -- Input feature -- Input
data: STRING_8 read_character
local -- Read the next character in input stream.
d: like internal_data -- Make the result available in `last_character'
do do
d := internal_data index := index + 1
if d = Void then if index > chunk_upper then
d := fetched_data read_chunk
internal_data := d if last_chunk = Void then
read_trailer
end
end end
Result := d last_character := last_chunk.item (index)
end 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 feature {NONE} -- Parser
internal_data: detachable STRING_8 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 tmp_hex_chunk_size: STRING_8
last_chunk_size: INTEGER
last_chunk: detachable STRING_8
fetched_data: STRING_8 -- fetched_data: STRING_8
-- Read all the data in a chunked stream. -- -- Read all the data in a chunked stream.
-- Make the result available in `last_chunked'. -- -- Make the result available in `last_chunked'.
-- Chunked-Body = *chunk -- -- Chunked-Body = *chunk
-- last-chunk -- -- last-chunk
-- trailer -- -- trailer
-- CRLF -- -- CRLF
-- chunk = chunk-size [ chunk-extension ] CRLF -- -- chunk = chunk-size [ chunk-extension ] CRLF
-- chunk-data CRLF -- -- chunk-data CRLF
-- chunk-size = 1*HEX -- -- chunk-size = 1*HEX
-- last-chunk = 1*("0") [ chunk-extension ] CRLF -- -- last-chunk = 1*("0") [ chunk-extension ] CRLF
-- chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) -- -- chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
-- chunk-ext-name = token -- -- chunk-ext-name = token
-- chunk-ext-val = token | quoted-string -- -- chunk-ext-val = token | quoted-string
-- chunk-data = chunk-size(OCTET) -- -- chunk-data = chunk-size(OCTET)
-- trailer = *(entity-header CRLF) -- -- trailer = *(entity-header CRLF)
local -- local
eoc: BOOLEAN -- eoc: BOOLEAN
s: STRING_8 -- s: STRING_8
do -- do
from -- from
create s.make (1024) -- create s.make (1024)
until -- until
eoc -- eoc
loop -- loop
read_chunk -- read_chunk
if attached last_chunk as l_last_chunk then -- if attached last_chunk as l_last_chunk then
s.append (l_last_chunk) -- s.append (l_last_chunk)
else -- else
eoc := True -- eoc := True
end -- end
if last_chunk_size = 0 then -- if last_chunk_size = 0 then
eoc := True -- eoc := True
end -- end
end -- end
read_trailer -- read_trailer
Result := s -- Result := s
end -- end
reset_chunk
do
last_chunk := Void
last_chunk_size := 0
end
read_chunk read_chunk
do do
reset_chunk chunk_lower := chunk_upper + 1
last_chunk.wipe_out
last_chunk_size := 0
read_chunk_size read_chunk_size
if last_chunk_size > 0 then if last_chunk_size > 0 then
chunk_upper := chunk_upper + last_chunk_size
read_chunk_data read_chunk_data
end end
ensure
attached last_chunk as l_last_chunk implies l_last_chunk.count = chunk_upper - chunk_lower
end end
read_chunk_data read_chunk_data
require require
last_chunk.is_empty
last_chunk_size > 0 last_chunk_size > 0
local local
l_input: like input l_input: like input
@@ -105,12 +194,6 @@ feature {NONE} -- Parser
l_input := input l_input := input
l_input.read_string (last_chunk_size) l_input.read_string (last_chunk_size)
last_chunk := l_input.last_string last_chunk := l_input.last_string
-- read CRLF
l_input.read_character
if l_input.last_character = '%R' then
l_input.read_character
end
ensure ensure
last_chunk_attached: attached last_chunk as el_last_chunk last_chunk_attached: attached last_chunk as el_last_chunk
last_chunk_size_ok: el_last_chunk.count = last_chunk_size last_chunk_size_ok: el_last_chunk.count = last_chunk_size

View File

@@ -27,9 +27,18 @@ feature {NONE} -- Initialization
input := a_input input := a_input
set_meta_variables (a_vars) set_meta_variables (a_vars)
update_path_info 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 is_chunked_input := True
create chunked_input.make (a_input) create {WGI_CHUNKED_INPUT_STREAM} input.make (input)
end end
end end
@@ -40,9 +49,7 @@ feature -- Access: Input
input: WGI_INPUT_STREAM input: WGI_INPUT_STREAM
-- Server input channel -- Server input channel
--| Could be a chunked input as well
chunked_input: detachable WGI_CHUNKED_INPUT_STREAM
-- Chunked server input channel
feature -- EWSGI access feature -- EWSGI access

View File

@@ -11,44 +11,30 @@ feature {NONE} -- Implementation
full_input_data (req: WSF_REQUEST): READABLE_STRING_8 full_input_data (req: WSF_REQUEST): READABLE_STRING_8
do do
if req.is_chunked_input then Result := read_input_data (req.input)
if attached req.chunked_input as l_chunked_input then
Result := l_chunked_input.data
else
check has_chunked_input: False end
Result := ""
end
else
Result := read_input_data (req.input, req.content_length_value)
end
end end
read_input_data (a_input: WGI_INPUT_STREAM; nb: NATURAL_64): STRING_8 read_input_data (a_input: WGI_INPUT_STREAM): STRING_8
-- All data from input form -- All data from input form
local local
nb32: INTEGER
n64: NATURAL_64
n: INTEGER n: INTEGER
t: STRING t: STRING
do do
from from
n64 := nb n := 1_024
nb32 := n64.to_integer_32 create Result.make (n)
create Result.make (nb32)
n := nb32
if n > 1_024 then
n := 1_024
end
until until
n64 <= 0 n = 0
loop loop
a_input.read_string (n) a_input.read_string (n)
t := a_input.last_string t := a_input.last_string
Result.append_string (t) if t.count = 0 then
if t.count < n then n := 0
n64 := 0
else else
n64 := n64 - t.count.as_natural_64 if t.count < n then
n := 0
end
Result.append_string (t)
end end
end end
end end

View File

@@ -157,26 +157,17 @@ feature -- Access: Input
input: WGI_INPUT_STREAM input: WGI_INPUT_STREAM
-- Server input channel -- Server input channel
require
is_not_chunked_input: not is_chunked_input
do do
Result := wgi_request.input Result := wgi_request.input
end end
is_chunked_input: BOOLEAN is_chunked_input: BOOLEAN
-- Is request using chunked transfer-encoding? -- Is request using chunked transfer-encoding?
-- If True, the Content-Length has no meaning
do do
Result := wgi_request.is_chunked_input Result := wgi_request.is_chunked_input
end end
chunked_input: detachable WGI_CHUNKED_INPUT_STREAM
-- Server input channel
require
is_chunked_input: is_chunked_input
do
Result := wgi_request.chunked_input
end
feature -- Helper feature -- Helper
is_request_method (m: READABLE_STRING_8): BOOLEAN is_request_method (m: READABLE_STRING_8): BOOLEAN